This question already has answers here:
In JavaScript, why is "0" equal to false, but when tested by 'if' it is not false by itself?
(15 answers)
Closed 8 years ago.
Why is the result of the following two statements different?
('0' ? 'a' : 'b') /* -> 'a' */
('0' == true ? 'a' : 'b') /* -> 'b' */
jsFiddle testcase
Edit:
I should add that I suspect the '0' first statement to be cast to boolean to be compared - which should be exactly the same as " '0' == true "
Obviously this is not true.
First, for completeness:
('0' ? 'a' : 'b')
is 'a', because '0' is a non-empty string, which always evaluates to true:
String: The result is false if the argument is the empty String (its length is zero);
otherwise the result is true.
Now to '0' == true.
Two type conversions will take place here. We can follow this in the specification, section 11.9.3, The Abstract Equality Comparison Algorithm.
The operands are denoted as x and y (x == y).
In our case, x is a string ('0') and y is a Boolean (true). Hence step 7 is executed:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
When booleans are converted to numbers, the following conversion takes place:
Boolean: The result is 1 if the argument is true. The result is +0 if the argument is false.
Now we have
'0' == 1
which matches the condition in step 5:
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
How strings are converted to numbers is more complex but of course can also be found in the specification.
So the final comparison is
0 == 1
which is false (step 1. a. vi.)
('0' ? 'a' : 'b'); /* -> 'a' */
0 is a string value, every non-empty string is evaluated as true, and not tested as boolean. If quotes are removed:
(0 ? 'a' : 'b'); /* -> 'b' */
you will receive b - now 0 is not a string and evaluated as false!
('0' == true ? 'a' : 'b'); /* -> 'b' */
0 is evaluated as bool Both are evaluated as numbers, which is false. Point 11.9.3 The Abstract Equality Comparison Algorithm from the specs show that a number of conversions may be executed to compare the same type of variables.
Because '0' is not equal 1, so it is not equal to true, though it is not false.
In the first case, when '0' is casted to bool, casting operator returns true for everything that is not 0.
Mostly because JavaScript is pretty darn inconsistent when it comes to truth-iness. But the answer is:
In this case, '0' is converted directly to a Boolean, and '0', being a non-empty string, is true.
In this case, no conversion takes place; a string is not equal to a boolean value.
That's because '0' is trueish (in an if statement), but not considered equal to true. Just like both 3 and 17 are trueish, but not equal.
('0' ? 'a' : 'b') --> 0 is false, '0' is some string therefore NOT FALSE
0,null or '' (empty string) is treated as FALSE in this case
('0' == true ? 'a' : 'b') --> as mentioned by others some_string compared to boolean TRUE is NOT TRUE
Related
This question already has answers here:
Can't understand the conditional execution flow [duplicate]
(3 answers)
Closed 3 years ago.
I thought I knew about the quirks with == and all the strange type casts in JavaScript, but today I stumbled upon one thing that doesn't make any sense to me:
'\t' == false
// => true
Why is that?
Apparently, '\t' is not a falsy value, and if combined with || it works as excpected:
'\t' || 42
// => '\t'
On the other hand, a toString is also not called on false, see:
'\t' == 'false'
// => false
This led me to thinking that the tab maybe gets converted to a boolean, but:
Boolean('\t') == false
// => false
So, the question is: Why is that?
See Abstract Equality Comparison::
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
So, in your situation, x is a string, and y is a boolean. The first condition that is fulfilled here is:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
Turning the check into
'\t' == 0
Which then fulfills:
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
And ToNumber('\t') === 0:
console.log(Number('\t'));
Turning the check into
0 == 0
which is the same as
0 === 0
or true.
Note that while a string composed of all whitespace is == false, calling Boolean on such a string will return true, because the string has a non-zero length:
console.log(
Boolean(' '),
Boolean('\t')
);
Of course, it would be best to always avoid == - use === instead, and you won't have to worry about these silly coercion rules.
I am trying to understand the core of JavaScript. I know it doesnt have much implementation value. If you dont want to answer, just leave it. However, I will appreciate if you could help to understand the following type coercion while applying addition(+).
1.
null + null // 0
2.
null + undefined; // NaN
3.
null + NaN; // NaN
4.
1 + null; //1
5.
true + null; //1
6.
true + [null]; //"true"
I know null is an empty or missing object. I will appreciate, if you can explain steps in type coercion or unary(+) operation here. Thanks for reading the question.
This is covered in 11.6.1 The Addition operator ( + ) - feel free to read it and follow the rules.
The first five cases can be explained by looking at ToNumber:
Value ToNumber(Value)
--------- ---------------
null 0
undefined NaN
NaN NaN
1 1
true 1
And 0 + 0 == 0 (and 1 + 0 == 1), while x + NaN or NaN + x evaluates to NaN. Since every value above is also a primitive, ToPrimitive(x) evaluates to x (where x is not a string) and the "string concatenation clause" was not invoked.
The final case is different in that it results from the ToPrimitive (which ends up calling Array.prototype.toString) on the array which results in a string value. Thus it ends up applying ToString, not ToNumber, and follows as such:
true + [null]
=> true + "" // after ToPrimitive([null]) => ""
=> "true" + "" // after ToString(true) => "true"
=> "true" // via String Concatenation
Conclusions derived from analysing results
true coerces to 1 (and false to 0).
null coerces to 0.
undefined coerces to NaN.
Arrays behave as:
under unary + (+[]):
their first element if length is 1
0 if they're empty
NaN if there's more than 1 element
under binary + (1+[]):
coerces both operators to strings and joins them
All operations on NaN return NaN
My app behaves abnormally and figured the code below is going to else statement unexpectedly.
code
if(" " != 0) {
console.log("whitespace is not zero");
}
else {
console.log("bar");
}
Firebug output
bar
I thought whitespace is a String and comparison against integer zero should return false like the case above but I don't know why it is going to else statement.
Could anyone explain why?
In JS, " " == 0 equals true with loose/lenient comparison, you should use strict equality operator ===/!== instead:
" " !== 0
To get to first condition.
Tests:
console.log(" " == 0); // true
console.log(" " === 0); // false
Loose Comparison Chart:
"" == "0" // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true
Strict Comparison Chart:
"" === "0" // false
0 === "" // false
0 === "0" // false
false === "false" // false
false === "0" // false
false === undefined // false
false === null // false
null === undefined // false
" \t\r\n" === 0 // false
(Examples by Douglas Crockford)
Good Practice:
Whenever possible, use strict equality operator because with loose equality operator, JS does type coercion which is a performance hit and doesn't always yield expected results as shown in above comparison charts.
The other answers have told you how to solve the issue. My answer will attempt to actually explain why you have the issue in the first place (since that was your actual question!)
The behaviour of the == operator is defined in the spec as the "abstract equality algorithm". It states (among other things) the following:
If Type(x) is String and Type(y) is Number, return the result of the
comparison ToNumber(x) == y.
One of the rules of the ToNumber operation on a string is as follows:
The MV of StringNumericLiteral ::: StrWhiteSpace is 0...
Once the exact MV for a String numeric literal has been determined, it is then rounded to a value of the Number type. If the MV is 0, then the rounded value is +0 unless the first non white space character in the String numeric literal is ‘-’, in which case the rounded value is −0.
So we are left with +0 == 0 which fits another rule of the abstract equality algorithm:
If x is the same Number value as y, return true.
This is the case because 0 is the same as +0. Even if one of the numbers was -0 it would return true:
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return
true.
When you use != rather than !==, JavaScript tries to coerce the values on either side to the same type. In this case, I think it converts both to numbers.
" " happens to be 0 as a number. (Try " " * 1. It evaluates to 0.)
This also works with other operators like > or *. So " " > -1 is true and " " * 100 is 0. This also means you can do neat stuff like "6" * "7" and get 42. Unfortunately, this breaks down with + since it is inexplicably overloaded to do both math and string concatenation.
I personally like all of this behavior except for +. Others' opinions vary.
to compare with the number 0, you must use the strict comparison ===
if(" " !== 0) {
console.log("whitespace is not zero");
}
else {
console.log("bar");
}
a "truth table" found here: Which equals operator (== vs ===) should be used in JavaScript comparisons?
because a string with whitespaces is converted to 0. So
To compare:
if(" " !== 0) {
....
Consider empty JavaScript array:
var a = [];
alert(a == false); // shows true
alert(!a); // shows false!
How to explain this?
What are the rules?
From http://forums.whirlpool.net.au/archive/966449:
a == false:
In this case, the type of the left-hand side is object, the type of the right-hand side is boolean. Javascript first converts the boolean to a number, yielding 0. Then it converts the object to a "primitive", yielding the empty string. Next it compares the empty string to 0. The empty string is converted to a number, yielding 0, which is numerically equal to the 0 on the right-hand side, so the result of the entire expression is true.
See §11.9.3 of the ECMAScript spec for all the gory details.
(!a):
In this case Javascript converts the object to the boolean true, then inverts it, resulting in false.
The ! operator checks whether its operand is "falsy".
The following are true:
!false
!0
!null
!NaN
!undefined
!""
The == operator checks for loose equality, which has nothing to do with falsiness.
Specifically, a == b 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
The == operator when one of the operands if Boolean, type-converts the other to Number.
[] == 0;
Is equivalent to:
0 == 0;
You can see the complete details of The Abstract Equality Comparison Algorithm on the specification.
As you can see, an empty array object, when converted to Number, produces 0:
+[]; // 0
Number(0);
This is really because its toString method produces an empty string, for example:
[].toString(); // ""
+""; // 0
Number(""); // 0
When comparing an object to a primitive value via the == operator, the object coerces into an primitive value itself (number or string). In this case [] coerces into 0, then false coerces into 0:
[] == false
0 == false
0 == 0
which is true.
The ! operator coerces into boolean and then inverts the value. [] into boolean is true (like with any object). Then invert to become false
![]
!true
false
Not sure if this answers the question, but there is a new library for getting around all of Javascript's Typecasting weirdnesses:
Typecast.js
In a sentence, Typecast solves all the simple problems, so you can focus on the big ones. Typecast fixes what's wrong with Javascript by creating a complete platform for strongly-typed variables in Javascript.
Code-snippet 1:
if ( !x ) { /* do stuff */ }
Code-snippet 2:
if ( x == 0 ) { /* do stuff */ }
For what values of x do these two code-snippets differ?
I am asking because, although I read the chapter on == in the spec, I still find it hard to deal with situations like the above (where it is combined with ToBoolean coercion).
btw, I want to know this just for the sake of knowing it (I want to understand the language), so don't bother telling me about === or asking me what x is.
Update: I corrected the fist snippet. I meant !x.
[] == 0 is true; ![] is false
null == 0 is false; !null is true
NaN == 0 is false; !NaN is true
undefined == 0 is false; !undefined is true
!x will check whether x is "falsy".
x == 0 will check whether x is "equivalent to" 0.
Both of these terms are defined by the Javascript spec.
The following will give you true for the first and false for the second snippet:
NaN
null
undefined
And these will give you false for the first and true for the second snippet:
[]
"0" and any other string that converts to 0 using Number(x) such as "00", "000", "+0", and "-0" (which I will now call "noughty strings")
an array containing a single element that is 0, null, undefined or an empty or noughty string.
For everything else you'll get the same result for both snippets, although there may be one or two more cases I haven't thought of.
Here's an interesting one with regard to a non-empty String that has only space characters:
!!" "; // true
" " == true; // false
This is because when you do a == comparison, and one of the values being compared is a number or a boolean, an attempt is made to convert the other value to a number.
The reason you get the different result is that a string with only space characters converts to the number 0 (or falsey), while a string with only spaces converted to boolean via !! is seen as a non-empty string, and therefore true.
So:
var x = " ";
alert( !x ); // false
alert( x == 0 ); // true
EDIT:
Probably the key thing to remember is that when comparing a number or boolean to a non number type, == uses toNumber conversion if possible, while ! uses toBoolean conversion. They're not always the same.
It is easy to see the result of the toBoolean conversion using !!. As in:
alert( !![] ); // true
But you can't really see the result of the toNumber conversion when using ==.
You can, however, use the unary + to see the result of a toNumber conversion. As in:
alert( +[] ); // 0
I'm pretty sure that what happens in the case of an Array, is that it first gets a toString call. Therefore:
// ---------------------toString result-------toNumber result (from string)
alert( +[] ); // "" 0
alert( +[""] ); // "" 0
alert( +[" "] ); // " " 0
alert( +[0] ); // "0" 0
alert( +["0"] ); // "0" 0
alert( +["3"] ); // "3" 3
alert( +[3,4] ); // "3,4" NaN
Short answer: the two are almost always the same but not 100% the same.
An example would be (!'0') which is false whereas ('0' == 0) is true
Details:
From: http://www.joeyjavas.com/2007/08/04/javascript-true-false-checking-for-boolean-values/
Checking if a value is true or false is simple in JavaScript. All values evaluate to true, except for:
0
-0
null
undefined
NaN
empty string
false
Therefore, (!x) will be true for all of the above values of x and only those.
As for (x == 0), it will be true for any value of x which - when converted according to "==" conversion rules - is converted to 0 when compared to a number (for example, Boolean false value). Other examples that compare true to ==0 are objects which generate 0 from their valueOf() methods, or a string '0', or an empty Array ([])
The first test will succeed when x is non-zero, or evaluates to an object (as opposed to null or undefined), or is a non-empty string. So if x is 0 then the condition fails, but if it is "0" then it succeeds.
The second test will succeed when x is convertible to 0. This means it must not be null, undefined, or an object to pass this test. And it may be "0" or "".
In other words, these conditionals are not opposites. The value "0" will pass both tests, for example.
Code Snippet 1 will execute if x is "falsy" value. In Javascript, this means 0, -0, null, undefined, NaN, "", or false. Code Snippet 2, however, will only execute if x is zero. Unlike the first condition, this does not include other "falsy" values.
The difference between the two is that
if ( x ) { ... }
Tests whether x is "truthy"
Whereas
if ( x == 0 ) { ... }
Does type coercion between x and 0.
I presume you mean something like
if (x == 0) vs if (!x)
The main difference is type coercion of x to a number vs checking if x is falsy.
Clearly NaN itself will never equal 0 since its not a number. undefined will also coerce to NaN so that is not caught by == 0 I can't give a good explanation why null is not caught by 0 since Number(null) == 0
After some lookups, have to change my awnser.
There's no simple logic, implicit equality operations follows an algorithm.
http://interglacial.com/javascript_spec/a-11.html#a-11.9.3
I can't sum it up better then what the algoritm describes, it would just get more confusing.
So it's (!x) is equivalent to (typeof x === false) aka (not true)
And (x == 0) gets compared by algorithm.