Reputation: 13994
From what I know, the if
statement in JavaScript casts the result of its condition to a Boolean, and then executes it like the following:
if(true) {
// run this
}
if(false) {
// do not run this
}
And that works. But If I do this:
if('0' == false) {
// We get here, so '0' is a falsy value
}
Then I would expect this:
if('0') {
// We don't get here, because '0' is falsy value
}
But instead, I get:
if('0') {
// We *DO* get here, even though '0' is falsy value
}
What's happening? Apparently, if
does not check if its condition is a truthy or falsy value, but does some other conversion?
Upvotes: 5
Views: 4765
Reputation: 7719
This is just one of those "gotchas" with the ==
rules which are rather complex.
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
(4) If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
(5) If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
(6) If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
(7) If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
In this case, that means that '0' == false
is first coerced to '0' == 0
(by rule #7) and then, on the second pass through, it is coerced to 0 == 0
(by rule #5) which results in true.
This particular case is somewhat tricky because of false ~> 0
instead of '0' ~> true
(as what might be expected). However, '0'
is itself a truth-y value and the behavior can be explained with the above rules. To have strict truthy-falsey equality in the test (which is different than a strict-equality) without implicit conversions during the equality, consider:
!!'0' == !!false
(For all values: !falsey -> true
and !truthy -> false
.)
Upvotes: 7
Reputation: 415800
if ('0' == false)
:Javascript is doing something called type coercion
.
Following the rules in that link, we fall to rule 7:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y)
Calling ToNumber(false) gives us a numeric 0. The result now starts to make sense, but we're still not quite done, because we still have a string and a number. The process starts again, and this time we fall to rule 5:
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y: "2" == 2
This time, the left side '0' is converted to a number: 0. Now, at last, we can compare two Numbers, and since 0 equals 0, the result is true. However, it's important to note that this implies nothing at all about the truish/falsy nature of the '0'
string, because it was coerced before it was compared.
if('0')
In this case, there is no comparison; you only want to know if a single value is "truish" or "falsy". No type coercion is used, because strings can be evaluated as truish or falsy on their own merits. Using the rules at the same link as before, we find this information:
In JavaScript, and not only JavaScript, we have so called falsy values. These are respectively: 0, null, undefined, false, "", NaN. Please note the empty string is empty, 'cause differently from php as example, "0" will be considered truish
The quote is especially helpful because it specifically calls out the '0' string, but that would not be necessary. It's enough to know that an empty string is falsy, and any other string is truish, because the content of the string is not evaluated and no coercion is performed. 0
may be a falsy value, but because we evaluate a string rather than coercing to a number, and '0'
has a value of some kind, it is still truish.
Upvotes: 3
Reputation: 114481
Javascript operator ==
does type conversion and is basically useless. Just avoid it.
For example:
[]
is truty but [] == false
is true1 == "1"
, [1] == "1"
, [[1]] == "1"
are all true[1] == [[1]]
however is falseThe rules are VERY weird. For example in the first case []
gets converted to ""
that gets converted to a number and the value is 0
. false
is also converted to the number 0
. So in the end they compare equal.
Note however that while the conversion from the empty string to a number gives 0
, the result of parseInt("")
is NaN
.
PS: The real fun is when you discover that [30,20,10,3,2,1].sort()
returns [1,10,2,20,3,30]
(yes... numbers, yes in lexicographical order). No I'm not kidding.
Upvotes: 1
Reputation: 707326
This:
if('0') {
// We *DO* get here, even though '0' is falsy value
}
checks to see if the string is null or empty, not whether it's zero or not. Any non-empty string is truthy.
When you do this:
if('0' == false) {
// We get here, so '0' is a falsy value
}
you are asking the JS engine for an explicit type conversion to try to match the type of the two operands. That is different than just asking if one operand is truthy all by itself.
In general, you will find that you get fewer unexpected results if you nearly always use ===
and !==
and only allow type coercion when you know exactly what is going to happen in all cases either because you fully understand the very complex coercion rules or because you know what types will be present and you understand those specific cases.
Upvotes: 3