console.log("20">10); //true
console.log("20a">"10"); //true
console.log("20a">10); //false
I want to know why the last one turns false.
And "20a" transforms to what before comparing.
From the MDN page on comparison operators:
For relational abstract comparisons (e.g. <=), the operands are first converted to primitives, then the same Type, before comparison.
console.log("20">10); //true
This converts "20" to a number 20 and compares it. Since 20 is greater than 10, it is true.
console.log("20a">"10"); //true
This compares the two strings. Since "20a" is greater (alphabetically) than "10", it is true.
console.log("20a">10); //false
This converts "20a" to a number. The result is NaN (do +"20a" to see this in action). NaN is not greater than any number, so it returns false.
The comparison algoritm in ECMAScript is described here : http://bclary.com/2004/11/07/#a-11.8.5
The comparison x < y, where x and y are values, produces true, false,
or undefined (which indicates that at least one operand is NaN). Such
a comparison is performed as follows:
Call ToPrimitive(x, hint Number).
Call ToPrimitive(y, hint Number).
3.If Type(Result(1)) is String and Type(Result(2)) is String, go to step 16. (Note that this step differs from step 7 in the algorithm for
the addition operator + in using and instead of or.)
4.Call ToNumber(Result(1)).
5.Call ToNumber(Result(2)).
...
So in case of "20a">10, the javascript engine must apply ToNumber to "20a". The complete algorithm is complex but states that
If the grammar cannot interpret the string as an expansion of
StringNumericLiteral, then the result of ToNumber is NaN.
So you're comparing NaN to 10 and any comparison involving NaN returns false (or undefined, see comments below).
For the last case, Notice that even "20a" < 10 return false. This highlights the evaluation of "20a" at NaN during the comparison, as NaN compared to any number always returns false.
Related
I'm familiar with NaN being "weird" in JavaScript, i.e., NaN === NaN always returns false, as described here. So one should not make === comparisons to check for NaN, but use isNaN(..) instead.
So I was surprised to discover that
> [NaN].includes(NaN)
true
This seems inconsistent. Why have this behavior?
How does it even work? Does the includes method specifically check isNaN?
According to MDN's document say that
Note: Technically speaking, includes() uses the sameValueZero
algorithm to determine whether the given element is found.
const x = NaN, y = NaN;
console.log(x == y); // false -> using ‘loose’ equality
console.log(x === y); // false -> using ‘strict’ equality
console.log([x].indexOf(y)); // -1 (false) -> using ‘strict’ equality
console.log(Object.is(x, y)); // true -> using ‘Same-value’ equality
console.log([x].includes(y)); // true -> using ‘Same-value-zero’ equality
More detailed explanation:
Same-value-zero equality similar to same-value equality, but +0 and −0 are considered equal.
Same-value equality is provided by the Object.is() method: The only difference between Object.is() and === is in their treatment of signed zeroes and NaNs.
Additional resources:
Which equals operator (== vs ===) should be used in JavaScript comparisons?
Array.prototype.includes vs. Array.prototype.indexOf
Are +0 and -0 the same?
The .includes() method uses SameValueZero algorithm for checking the equality of two values and it considers the NaN value to be equal to itself.
The SameValueZero algorithm is similar to SameValue, but the only difference is that the SameValueZero algorithm considers +0 and -0 to be equal.
The Object.is() method uses SameValue and it returns true for NaN.
console.log(Object.is(NaN, NaN));
The behavior of .includes() method is slightly different from the .indexOf() method; the .indexOf() method uses strict equality comparison to compare values and strict equality comparison doesn't consider NaN to be equal to itself.
console.log([NaN].indexOf(NaN));
Information about different equality checking algorithms can be found at MDN:
MDN - Equality comparisons and sameness
Specs
This appears to be part of the Number::sameValueZero abstract operation:
6.1.6.1.15 Number::sameValueZero ( x, y )
If x is NaN and y is NaN, return true.
[...]
This operation is required to be part of the Array#includes() check which does:
22.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] )
[...]
Repeat, while k < len
a. Let elementK be the result of ? Get(O, ! ToString(k)).
b. If SameValueZero(searchElement, elementK) is true, return true.
c. Set k to k + 1.
Return false.
[...]
Where the SameValueZero operation will delegate to the one for numbers at step 2:
7.2.12 SameValueZero ( x, y )
[...]
If Type(x) is different from Type(y), return false.
If Type(x) is Number or BigInt, then
a. Return ! Type(x)::sameValueZero(x, y).
Return ! SameValueNonNumeric(x, y).
For comparison Array#indexOf() will use Strict Equality Comparison which is why it behaves differently:
const arr = [NaN];
console.log(arr.includes(NaN)); // true
console.log(arr.indexOf(NaN)); // -1
Other similar situations
Other operations that use SameValueZero for comparison are in sets and maps:
const s = new Set();
s.add(NaN);
s.add(NaN);
console.log(s.size); // 1
console.log(s.has(NaN)); // true
s.delete(NaN);
console.log(s.size); // 0
console.log(s.has(NaN)); // false
const m = new Map();
m.set(NaN, "hello world");
m.set(NaN, "hello world");
console.log(m.size); // 1
console.log(m.has(NaN)); // true
m.delete(NaN);
console.log(m.size); // 0
console.log(m.has(NaN)); // false
History
The SameValueZero algorithm first appears in the ECMAScript 6 specifications but it is more verbose. It still has the same meaning and still has an explicit:
7.2.10 SameValueZero(x, y)
[...]
If Type(x) is Number, then
a. If x is NaN and y is NaN, return true.
[...]
ECMAScript 5.1 only has a SameValue algorithm which still treats NaN equal to NaN. The only difference with SameValueZero is how +0 and -0 are treated: SameValue returns false for them, while SameValueZero returns true.
SameValue is mostly used for internal object operation, so it is almost inconsequential for writing JavaScript code. A lot of the uses of SameValue are when working with object keys and there are no numeric values.
The SameValue operation is directly exposed in ECMAScript 6 as that is what Object.is() uses:
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0)); // false
Of slight interest is that WeakMap and WeakSet also use SameValue rather than SameValueZero that Map and Set use for comparison. However, WeakMap and WeakSet only allow objects as unique members, so attempting to add a NaN or +0 or -0 or other primitives leads to an error.
In 7.2.16 Strict Equality Comparison, there is the following note:
NOTE
This algorithm differs from the SameValue Algorithm in its treatment of signed zeroes and NaNs.
This means for Array#includes a different comparison function than for a strict comparison:
22.1.3.13 Array.prototype.includes under
NOTE 3
The includes method intentionally differs from the similar indexOf method in two ways. First, it uses the SameValueZero algorithm, instead of Strict Equality Comparison, allowing it to detect NaN array elements. Second, it does not skip missing array elements, instead of treating them as undefined.
As you can see reading include documentation, it does use the sameValueZero algorithm to work, so as its documentation say, it gives a True value when comparing NaN and I quote:
We can see from the sameness comparisons table below that this is due to the way that Object.is handles NaN. Notice that if Object.is(NaN, NaN) evaluated to false, we could say that it fits on the loose/strict spectrum as an even stricter form of triple equals, one that distinguishes between -0 and +0. The NaN handling means this is untrue, however. Unfortunately, Object.is has to be thought of in terms of its specific characteristics, rather than its looseness or strictness with regard to the equality operators.
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
}
As far as I know, in math both Infinity and NaN are vague values.
as all of us know:
console.log(NaN == NaN); //-> false
while
console.log(Infinity==Infinity); //-> true
I'm wondering why the result of the second code is true. I'm expecting that the result of the second one, should be false, but it's not.
Could you please help me out.
I'd really appreciate it. Thanks.
This is why:
NaN compares unequal (via ==, !=, ===, and !==) to any other value -- including to another NaN value. Use Number.isNaN() or isNaN() to most clearly determine whether a value is NaN. Or perform a self-comparison: NaN, and only NaN, will compare unequal to itself.
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN
The initial value of Infinity is Number.POSITIVE_INFINITY. The value Infinity (positive infinity) is greater than any other number. This value behaves mathematically like infinity; for example, any positive number multiplied by Infinity is Infinity, and anything divided by Infinity is 0.
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity
What you also might be interested in is using the isFinite method of Number:
Number.isFinite(Infinity); // false
Number.isFinite(NaN); // false
Read up on Number.isFinite(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite
In addition to the other answers: Because the spec says so.
NaN is the only value in JavaScript that is not equal to itself:
A reliable way for ECMAScript code to test if a value X is a NaN is an expression of the form X !== X. The result will be true if and only if X is a NaN.
http://www.ecma-international.org/ecma-262/5.1/#sec-15.1.2.4
Because processors interpret it that way. Most math in JS follows the IEEE-754 specification for floating math arithmetic, which processors implement in pretty specific ways. That includes NaN !== NaN and Infinity === Infinity, among other things.
infinity is treated as a numeric value, so infinity==infinity represents one numeric value equaling another. While in common mathematics the infinity can not be compared against infinity, in javascript it can!
NaN on the other hand, is a type of undefined variable, not a number. So comparisons between NaN are not logically comparable. The proper way to compare against NaN is with the function isNaN.
Example:
isNaN(NaN) // returns true
I’ve heard of boolean arithmetic and thought of giving it a try.
alert (true+true===2) //true
alert (true-true===0) //true
So algebra tells me true=1
alert (true===1) //false :O
Could someone explain why this happens?
=== is the strict equality operator. Try == operator instead.
true==1 will evaluate to true.
The strict equality operator === only considers values equal if they
have the same type. The lenient equality operator == tries to
convert values of different types, before comparing like strict
equality.
Case 1:
In case of true===1, The data type of true is boolean whereas the type of 1 is number. Thus the expression true===1 will evaluate to false.
Case 2:
In case of true+true===2 and true-true===0 the arithmetic operation is performed first(Since + operator takes precedence over ===. See Operator Precedence) and then the result is compared with the other operand.
While evaluating expression (true+true===2), the arithmetic operation true+true performed first producing result 2. Then the result is compered with the other operand. i.e. (2==2) will evaluate to true.
Because comparing data TYPE and value (that's what operator '===' does ), TRUE is not exactly the same as 1. If you changed this to TRUE == 1, it should work fine.
At the beginning, you're doing bool + bool. The + operator takes precedence over the === operator so it's evaluated first. In this evaluation, it's converting the booleans to their number forms. Run console.log(true + true); and this will return 2. Since you're comparing the number 2 to the number 2, you get a return value true with the strict equality.
When you're just comparing true === 1, like everyone else said you're comparing the boolean true to the number 1 which is not strictly equal.
first 2 expression are true because you are using expression (true+true) (true-true) it convert type of a value first due to expression and check equality with "===", toNumber and toPrimitive are internal methods which convert their arguments (during expression ) this is how conversion take place during expression
That's why true+true equal to the 2
In your third expression you are using === this not convert arguments just check equality with type, to make it true both values and there type must be same.
Thats all
I always thought that JavaScript's if statements did some kind of casting magic to their arguments, but I'm a little wary of what's actually going on behind the scenes.
I recently found a JavaScript comparison table and noticed that even though -1 == true evaluates to false, if(-1){...} will execute.
So within JavaScripts if statements, what happens to the expression? It seems reasonable to assume that it uses !!{expression} to cast it to an inverse boolean, then invert it again, but if that's the case, how does JS decide whether an object's inverse boolean representation is truthy or not?
JavaScript is wonky.
Yes, -1 == true results in false, but that's not what the if statement is doing. It's checking to see if the statement is 'truthy', or converts to true. In JavaScript, that's the equivalent of !!-1, which does result in true (all numbers other than zero are truthy).
Why?!?
The spec defines the double equals operator to do the following when presented with a number and a boolean:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
ToNumber will convert the boolean true into the number 1, so you're comparing:
-1 == 1
which anyone can tell you is clearly false.
On the other hand, an if statement is calling ToBoolean, which considers any non-zero, non-NaN number to be true.
Any JavaScript developer really needs to look at the documentation -- for this case, located here: http://www.ecma-international.org/ecma-262/5.1/#sec-9.2
9.2 ToBoolean
The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:
Argument Type Result
Undefined false
Null false
Boolean The result equals the input argument (no conversion).
Number The result is false if the argument is +0, −0, or NaN; otherwise the result is true.
String The result is false if the argument is the empty String (its length is zero); otherwise the result is true.
Object true
(Sorry about the formatting, can't make a table here.)
From JavaScript The Definitive Guide
The following values convert to, and therefore work like, false:
undefined
null
0
-0
NaN
"" // the empty string
All other values, including all objects (and arrays) convert to, and work like, true. false, and the six values that convert to it, are sometimes called falsy values, and all other values are called truthy.
These things by themselves are falsy (or evaluate to false):
undefined
null
0
'' or ""
false
NaN
Everything else i truthy.
Truthy-ness or falsy-ness is used when evaluating a condition where the outcome is expected to be either truthy (true) or falsy (false).
In your example if(-1 == true), you are comparing apples and oranges. The compare is evaluated first (and resulted in false), and the results of that is used in your condition. The concept of truthyness/falsyness isn't applied to the operands the comparison.
When if state using with comparing variable different type js use .toString и .valueOf ( for more information check http://javascript.info/tutorial/object-conversion ) - just keep this in mind - it make so example much more easy to understand