I was perusing the underscore.js library and I found something I haven't come across before:
if (obj.length === +obj.length) { ... }
What is that + operator doing there? For context, here is a direct link to that part of the file.
The unary + operator can be used to convert a value to a number in JavaScript. Underscore appears to be testing that the .length property is a number, otherwise it won't be equal to itself-converted-to-a-number.
According to MDN:
The unary plus operator precedes its operand and evaluates to its
operand but attempts to converts it into a number, if it isn't
already. For example, y = +x takes the value of x and assigns that to
y; that is, if x were 3, y would get the value 3 and x would retain
the value 3; but if x were the string "3", y would also get the value
3. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a
number, because it does not perform any other operations on the
number. It can convert string representations of integers and floats,
as well as the non-string values true, false, and null. Integers in
both decimal and hexadecimal ("0x"-prefixed) formats are supported.
Negative numbers are supported (though not for hex). If it cannot
parse a particular value, it will evaluate to NaN.
It's a way of ensuring that obj.length is a number rather than a potential string. The reason for this is that the === will fail if the length (for whatever reason) is a string variable, e.g. "3".
It's a nice hack to check whether obj.length is of the type number or not. You see, the + operator can be used for string coercion. For example:
alert(+ "3" + 7); // alerts 10
This is possible because the + operator coerces the string "3" to the number 3. Hence the result is 10 and not "37".
In addition, JavaScript has two types of equality and inequality operators:
Strict equality and inequality (e.g. 3 === "3" expresses false).
Normal equality and inequality (e.g. 3 == "3" expresses true).
Strict equality and inequality doesn't coerce the value. Hence the number 3 is not equal to the string "3". Normal equality and inequality does coerce the value. Hence the number 3 is equal to the string "3".
Now, the above code simply coerces obj.length to a number using the + operator, and strictly checks whether the value before and after the coercion are the same (i.e. obj.length of the type number). It's logically equivalent to the following code (only more succinct):
if (typeof obj.length === "number") {
// code
}
Related
Quick and a silly question that got me confused.
What kind of error occurs if I use an assignment statement instead of a comparison statement? I need to check if the value of the counter variable is equal to 5.
The code:
if (counter = 5) { /* ==SOME CODE==*/}
VS
if (counter == 5) { /* ==SOME CODE==*/}
The easiest way to pick-up this problem is to reverse the order of the comparison.
Instead of:
if (someVar == 5)
Use:
if (5 == someVar)
This way, if you mess it up, you'll get an assignment error, since you can't assign a different value to the number 5. You can assign a different value to a number object that happens to hold the number 5, but you can't change the 5 itself. ;)
What kind of error occurs if I use an assignment statement instead of a comparison statement?
In your example i assume that a browser would not throw any errors.
I tested https://validatejavascript.com/ with this code:
let counter = 3;
if (counter = 5) {
alert('Will this ever show or always?');
}
A linter might generate a warning - for exmaple
validatejavascript.com threw: 3:5 error Unexpected assignment within an 'if' statement. (no-cond-assign) and
jshint.com threw: Expected a conditional expression and instead saw an assignment.
And based on your comment:
But I need to check if the value of the counter variable is equal to 5.
A simple assignment operator (=) is used to assign a value to a variable.
What you are looking for are operators for Equality comparisons and sameness
JavaScript provides three different value-comparison operations:
=== - Strict Equality Comparison ("strict equality", "identity", "triple equals")
== - Abstract Equality Comparison ("loose equality", "double equals")
Object.is provides SameValue (new in ES2015).
Which operation you choose depends on what sort of comparison you are
looking to perform. Briefly:
double equals (==) will perform a type conversion
when comparing two things, and will handle NaN, -0, and +0
specially to conform to IEEE 754 (so NaN != NaN, and -0 == +0);
triple equals (===) will do the same comparison as double equals
(including the special handling for NaN, -0, and +0)
but without type conversion; if the types differ, false is returned.
Object.is does no type conversion and no special handling for NaN, -0,
and +0 (giving it the same behavior as === except on those special
numeric values).
Note that the distinction between these all have to do with their
handling of primitives; none of them compares whether the parameters
are conceptually similar in structure. For any non-primitive objects x
and y which have the same structure but are distinct objects
themselves, all of the above forms will evaluate to false.
This question already has answers here:
Why does JavaScript handle the plus and minus operators between strings and numbers differently?
(7 answers)
Closed 7 years ago.
I read a book about operators in Javascript, and this confused me.
console.log("5"+1);
This would make "5" as a string. So the result would be 51.
console.log("5"-1);
This result would be 4. I know it converts "5" to 5, but why it isn't shown undefined as "a string minus a number"?
Update: So how about other languages? Are they more restrict?
Sadly, it was expected from JavaScript to ride on Java's success for promotion on its early days and the plus for string concatenation was adopted since Java used it.
So JavaScript tries hard to coerce strings into numbers for you, it really does, its just that the plus was taken for strings so....well...
While Javascript has many strenghts it was made in 10 days and has many hilarious aspects like this one, check this comedy gold
The + is a operator that means SUM when adding numbers and that means CONCATENATE when using Strings.
As the first is a STRING, it will continue concatenating a "5"+toString(1).
As the MINUS (-) operator does not work with String you are getting undefined.
If you want to use MINUS operator, you will need to do :
parseInt("5") -> It will give you 5, the number
parseInt("5")-1 = 4
"5"+1 = 51
parseInt("5")+1 = 6
Hope it will help you
Because when we use '+' it can be used in two different ways:-
1. as mathematical operator.
2. to concatenate strings
but '-' can only be used as mathematical operator.
Hence javascript considers '5' as numerics in case of '-' while '5' as string in case of '+'.
In javascript (+) operator operates the way described below
3+true will return 4 , (+) operator between a number and a boolean or two boolean will convert boolean to number , hence true is converted to 1 hence the result is 4
"2"+true will return "2true" , if one of the operand is string it will convert the other operand (number or boolean) to string and process the concatenation
-"12"+3 will return -9 , (-) operator in front of string will convert the string to number and will make it as -12 and return -9
According to the standard EcmaScript 262. The + and - operators behave differently when strings are involved. The first converts every value to a string. The second converts every value to a number.
From the standard:
If Type(lprim) is String or Type(rprim) is String, then Return the
String that is the result of concatenating ToString(lprim) followed by
ToString(rprim)
This rules implies that if in the expression there is a string value, all values involved in the + operation are converted to a string. In JavaScript when the + operator is used with strings, it concatenates them. This is why console.log("5"+1) returns "51". 1 is converted to a string and then, "5" + "1" are concatenated together.
Nevertheless, the above rule doesn't apply for the - operator. When you are using a - all values are converted to numbers according to the Standard (see below). Therefore, in this case, "5" is converted to 5 and then 1 is subtracted.
From the standard:
5 Let lnum be ToNumber(lval).
6 Let rnum be ToNumber(rval).
Operator definition from the standard EcmaScript 262.
Operator + : http://www.ecma-international.org/ecma-262/5.1/#sec-11.6.1
Operator - : http://www.ecma-international.org/ecma-262/5.1/#sec-11.6.2
Because of the type coercion and how it isn't very consistent in JavaScript, in the second case the "5" is converted to a number 5, and 1 is subtracted from it, giving you 4.
"5" could be coerced to 5 (Integer). That's why you get 4 as output.
However if you try:
console.log("text" - 1);
Text cannot be coerced, and the output is NaN
The subtraction operator (-) subtracts the number to the right of the operator from the number on the left.
When either of the operands are strings, an attempt is made to convert the strings to numbers.
Instead of using "5" if you try console.log("abc" - 1); it will prompt a error as NaN.
Just for the info:
The subtract operator has special rules to deal with the variety of type conversions present in JavaScript:
If the two operands are numbers, perform arithmetic subtract and return the result.
If either number is NaN, the result is NaN.
If Infinity is subtracted from Infinity, the result is NaN.
If –Infinity is subtracted from –Infinity, the result is NaN.
If –Infinity is subtracted from Infinity, the result is Infinity.
If Infinity is subtracted from –Infinity, the result is –Infinity.
If +0 is subtracted from +0, the result is +0.
If –0 is subtracted from +0, the result is –0.
If –0 is subtracted from –0, the result is +0.
If either of the two operands is not a number, the result is NaN.
I have seen code where strings were casted to numbers using the plus operator.
This would look something like:
var x ="5",y;
y = +x;
console.log(typeof y) //number
How does this work?
In fact, there are two + operators : the binary + operator and this one : the Unary + operator.
See how it's described in the MDN :
(Unary Plus)
The unary plus operator precedes its operand and evaluates to its
operand but attempts to converts it into a number, if it isn't
already. For example, y = +x takes the value of x and assigns that to
y; that is, if x were 3, y would get the value 3 and x would retain
the value 3; but if x were the string "3", y would also get the value
3. Although unary negation (-) also can convert non-numbers, unary plus is the fastest and preferred way of converting something into a
number, because it does not perform any other operations on the
number. It can convert string representations of integers and floats,
as well as the non-string values true, false, and null. Integers in
both decimal and hexadecimal ("0x"-prefixed) formats are supported.
Negative numbers are supported (though not for hex). If it cannot
parse a particular value, it will evaluate to NaN.
var x = "5",
y;
You're declaring two variables named respectively x and y. The former is set to hold the string "5", the latter holds the undefined value(since it's declared but not defined).
Then you're setting y to be the conversion in Number type of the string "5"(via the unary operator +), which is 5. So you're getting typeof y to be number.
The + operator is the unary operator. It evaluates an object trying to convert it into a number.
As far as I know in JavaScript !! is supposed to normalize a boolean value converting it to true or false from some other type. This would mean that the "0" converts to boolean true. On the other hand if I compare it with false it turns out that it is in fact false (as the result of the comparison is true). What rule am I missing here. I have tested it in IE and Opera.
The == operator checks for loose equality, which has nothing to do with truthiness.
Specifically, it will convert to operands to numbers, then compare the numbers.
Strings containing numbers convert to the numbers that they contain; booleans convert to 0 and 1.
Objects are converted by calling valueOf, if defined.
Thus, all of the following are true:
"1" == 1
"0" == false
"1" == true
"2" != true
"2" != false
({ valueOf:function() { return 2; } }) == 2
({ valueOf:function() { return 1; } }) == true
In the first case, a non-empty string is equivalent to true.
In the second case, because one operand is a boolean, both operands are converted to numeric values. I believe false converts to the numeric value 0 and the string "0" also converts to a numeric 0, resulting in 0 == 0 which is true.
Check out the Mozilla reference for operator behavior.
For the first expression, section 9.2 of ECMA-262 defines an abstract operation ToBoolean internally used by the logical NOT operator. It says:
String
The result is false if the argument is the empty String (its length is zero); otherwise the result is true.
For the second expression, JavaScript will perform type coercion when it attempts to compare these values of different data types. Douglas Crockford says that this is a misfeature. It would be false if you had used === instead of ==. The rules are rather complex, so you should directly look in section 11.9.3 of ECMA-262 for the details.
I understand that using the "===" compares type, so running the following code results in "not equal" because it's comparing a number type to a string type.
var a = 20;
var b = "20";
if (a === b) {
alert("They are equal");
} else {
alert("They are not equal");
}
But I dont understand how using the "==" to compare only the value results in the "They are equal" message.
var a = 20;
var b = "20";
if (a == b) {
alert("They are equal");
} else {
alert("They are not equal");
}
How are the values equal? Isn't the string "20" stored as the ASCII characters 50 and 48 (0110010 and 0110000 in binary) and 20 stored as the actual binary number 0010100?
EDIT: Thanks everyone! I think all the responses are great and have helped me understand this much better.
The == operator compares only the values of the variables. If the types are different, a conversion is operated. So the number 20 is converted to the string "20" and the result is compared.
The === operator compares not only the values, but also the types, so no cast is operated. In this case "20" !== 20
The JavaScript engine sees the a as a number and casts the b to number before the valuation.
When type conversion is needed, JavaScript converts String, Number, Boolean, or Object operands as follows.
When comparing a number and a string, the string is converted to a number value. JavaScript attempts to convert the string numeric literal to a Number type value. First, a mathematical value is derived from the string numeric literal. Next, this value is rounded to nearest Number type value.
If one of the operands is Boolean, the Boolean operand is converted to 1 if it is true and +0 if it is false.
If an object is compared with a number or string, JavaScript attempts to return the default value for the object. Operators attempt to convert the object to a primitive value, a String or Number value, using the valueOf and toString methods of the objects. If this attempt to convert the object fails, a runtime error is generated.
The problem with the == comparison is that JavaScript version 1.2 doesn't perform type conversion, whereas versions 1.1 and 1.3 onwards do.
The === comparison has been available since version 1.3, and is the best way to check of two variables match.
If you need your code to be compatible with version 1.1, 1.2 and 1.3 versions of JavaScript code, you should ensure that the variables all match as if it was an === comparison that was being performed.
Part of the definition of "==" is that the values will be converted to the same types before comparison, when possible. This is true of many loosely typed languages.
Javascript is designed such that a string containing numbers is considered "equal" to that number. The reason for that is simplicity of use for the case of users entering a number into an input field and the site validates it in JS -- you don't have to cast the entered string to a number before comparing.
It simplifies a common use case, and the === operator still allows you to compare with the type considered as well.
As far as I know JavaScript does automatic data type conversion on the fly - so maybe the variables are casted to equivalent types automatically.