Implied string comparison, 0=='', but 1=='1' - javascript

I was debugging something and discovered some strangeness in JavaScript:
alert(1=='') ==> false
alert(0=='') ==> true
alert(-1=='') ==> false
It would make sense that an implied string comparison that 0 should = '0'. This is true for all non-zero values, but why not for zero?

According to the Mozilla documentation on Javascript Comparison Operators
If the two operands are not of the same type, JavaScript converts the
operands then applies strict
comparison. If either operand is a
number or a boolean, the operands are
converted to numbers; if either
operand is a string, the other one is
converted to a string
What's actually happening is that the strings are being converted to numbers.
For example:
1 == '1' becomes 1 == Number('1') becomes 1 == 1: true
Then try this one:
1 == '1.' becomes 1 == Number('1.') becomes 1 == 1: true
If they were becoming strings, then you'd get '1' == '1.', which would be false.
It just so happens that Number('') == 0, therefore 0 == '' is true

When javascript does implicit type conversions, the empty string literal will match the 0 integer. Do your comparison like this and you'll get your expected result:
alert(1==='') ==> false
alert(0==='') ==> false
alert(-1==='') ==> false

ECMA-262, 3rd edition, 11.9.3 regarding x == y, step 16:
If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
The empty string '' gets converted to 0 before the comparison.

This is just one of the truly hideous mangles that went into the JavaScript compromise. '' and 0 are both uninitialized values (equal to boolean false) and, therefore, equal.
To protect yourself from weird bugs like this, it's better to always use the === operator.

Javascript, like PHP, is weakly typed*. So when you compare 0 to '', the JS engine converts them to a similar datatype. Since 0 and '' both equate to boolean(false), "false == false" is true.
*Weakly typed languages do not require variables to be any specific data type, so you can set one variable as a string, change it to int, float, and back to string without the processor throwing errors.

In many languages, the empty string can be coerced to false.
Beware of doing comparisons with == instead of ===:
alert('' == '0'); //false
alert(0 == ''); // true
alert(0 =='0'); // true
== is not transitive.

Related

Javascript: the confuse about comparison "2 == true"

Here is a javascript comparison:
2 == true //false
it's said, the reason why return false, is because the comparison convert the true to Number datatype, and result is 1:
console.info(Number(true)) // 1
My confuse is, why the comparison don't convert the number 2 to Boolean datatype
console.info(Boolean(2)) // true
and the 2 == true result could be true ?
I find the doc here:
Comparison Operators, which said:
If the two operands are not of the same type, JavaScript converts the
operands then applies strict comparison. If either operand is a number
or a boolean, the operands are converted to numbers if possible; else
if either operand is a string, the other operand is converted to a
string if possible. If both operands are objects, then JavaScript
compares internal references which are equal when operands refer to
the same object in memory.
== does implicit conversion to compare. In this case 2 is number and true is boolean. The conversion rule is "while comparing a number to boolean, boolean will be converted to number" hence
true is converted to 1
and 2 == 1 will be false.
//similarly,
2 == false; //false
As false will be converted to 0 and 2 cannot be equal to 0 either.
However, 1 == true. for the same reason as true would be converted to 1 and 1==1

why do both if('0'==false) and if('0') evaluate to true in Javascript?

So for what I know is that the if statement in Javascript casts the result of its condition to a Boolean, and then executes it likes 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
}
So what's happening? Apparently, if does not check if its condition a truthy or falsy value, but does some other conversion?
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 do '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.)
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.
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.
Javascript operator == does type conversion and is basically useless. Just avoid it.
For example:
[] is truty but [] == false is true
1 == "1", [1] == "1", [[1]] == "1" are all true
[1] == [[1]] however is false
The 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.

Why javascript treats 0 equal to empty string? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implied string comparison, 0='', but 1='1'
Executing the following case in javascript, I get 0 equal to '' (an empty string)
var a = 0;
var b = '';//empty string
if(a==b){
console.log('equal');//this is printed in console
}else{
console.log('not equal');
}
Could anyone guide that what is the reason behind this?
Quoting the doc (MDN):
Equal (==)
If the two operands are not of the same type, JavaScript converts the
operands then applies strict comparison. If either operand is a number
or a boolean, the operands are converted to numbers if possible; else
if either operand is a string, the other operand is converted to a
string if possible.
As a operand type here is Number, b gets converted to Number as well. And Number('') evaluates to 0.
This can be quite surprising sometimes. Consider this, for example:
console.log(0 == '0'); // true
console.log(0 == ''); // true
console.log('' == '0'); // O'RLY?
... or this:
console.log(false == undefined); // false
console.log(false == null); // false
console.log(null == undefined); // fal.... NO WAIT!
...and that's exactly why it's almost always recommended to use === (strict equality) operator instead.
0, "" (Empty String), false all technically have the same value, when typecasted. If you need to strictly treat them, you can use ===.
It is the same with similar programming languages, like PHP.
var a = 0;
var b = ''; //empty string
if(a == b){
console.log('equal'); //this is printed in console
}else{
console.log('not equal');
}
To make a strict comparison:
if(a === b){
console.log('equal');
}else{
console.log('not equal'); //this is printed in console
}
== operator in javascript don't compare types so 0=='' === true (because as a number string '' evaluates to 0) or 0==false === true (because bool false evaluates to 0) to compare types to you can use === operator.
Here you'll find useful information about comparison.
Javascript automatically converts variables of different types for comparison. That's a common feature in non-strictly typed languages.
If you need to compare variables and check the type, use the === operator.
In most programming language(including javascript) ""(string), 0(integer), \x0(null) losely mean the same thing: "empty". What's happening is your javascript engine finds "" == 0 false, due to the == it converts 0 to an integer. Again this is false, so it converts 0 to null which is false, so then it converts 0 to an empty string. (Not sure if this is the correct order of conversion). To make the condition "exact" match(no conversion) use === inplace of ==
== does typecasting. Always use ===.
In your example, the empty string of b is being converted to 0. So both a and b are the same.
Because empty string represented as number is zero. If you compare apples and oranges you should think of how your particular orange would look if it were an apple.
Because of coercion. It is usually a better idea to use === for comparisons in JavaScript.
Because == checks value equality so false, 0 and empty strings are equals. Use identity check ===.

Javascript if-statement vs. comparsion

Is it true that in if-statement JavaScript wrap the condition into a Boolean?
if(x) => if(Boolean(x))
Is it true that in comparison JavaScript wrap the compare elements into a Number?
a == b => Number(a) == Number(b)
Yes, and No.
For the first part, yes, that is essentially what the javascript does.
But for the latter, no. Not everything in JavaScript can be converted to a number. For example:
Number('abc') // => NaN
And Not-A-Numbers are not equal:
NaN == NaN // => false
So something like this:
Number('abc') == Number('abc') // => false!
But that's actually true with equality comparison.
'abc' == 'abc' // => true
As a side note, it's probably better to use === in JavaScript, which also checks the type of the values being compared:
0 == '0' // => true
0 === '0' // => false, because integer is not a string
More details about === can be read over here.
Yes, that's true, x is evaluated in a boolean context in this situation, so the equivalent of Boolean(x) is applied.
No, that's not true. It only looks that way because the coercitive equality operator == tries to convert a and b to the same type. Number() is only applied if either a or b is already a Number. For instance:
>>> 0x2A == 42
true // both 'a' and 'b' are numbers.
>>> "0x2A" == 42
true // 'a' is a string whose number coercion is equal to 'b'.
>>> "0x2A" == "42"
false // 'a' and 'b' are different strings.
Is it true that in if-statement JavaScript wrap the condition into a Boolean?
Usually yes.
Is it true that in comparison JavaScript wrap the compare elements into a Number?
Absolutely no.
Explanation
From JavaScript Language Specifications.
The if statement is defined at § 12.5 as:
if ( Expression ) Statement else Statement
It says that the Expression will be evaluated, converted with GetValue() and then tested after the ToBoolean() conversion.
Then the first assertion is true (but see later), the condition for the if statement is evaluated like is passed as parameter to the Boolean function. Please recall how JavaScript handles type conversion to boolean (§ 9.2):
undefined and null values are converted to false.
numbers are converted to false if ±0 or NaN otherwise they're converted to true.
strings are converted to false if empty otherwise always to true regardless their content.
objects are always converted to true.
Because of the call to GetValue() strictly speaking this assertion is not always true, take a look to § 8.7.1 where the standard describes how GetValue() works, here can happen some magic conversion before ToBoolean() is called.
The == operator is defined as in § 11.9.3.
As you can see it doesn't specify that operands must be (or will be treated as) numbers, the behavior of the operator is different and regulated by a series of rules based on the type of the operands. Then your second assertion is false. The case they're numbers (or one of them is a number) is just a special case in the algorithm, please note that at point 4 of the algorithm it says that if one of them is a number and the other one is a string then it'll be converted with ToNumber(), only in this case (with all the implications that this conversion has).
It's intuitive if you think that you can compare functions, strings or numbers, not every type can be converted to a numeric value.

In JavaScript, why is "0" equal to false, but when tested by 'if' it is not false by itself?

The following shows that "0" is false in Javascript:
>>> "0" == false
true
>>> false == "0"
true
So why does the following print "ha"?
>>> if ("0") console.log("ha")
ha
Tables displaying the issue:
and ==
Moral of the story use ===
table generation credit: https://github.com/dorey/JavaScript-Equality-Table
The reason is because when you explicitly do "0" == false, both sides are being converted to numbers, and then the comparison is performed.
When you do: if ("0") console.log("ha"), the string value is being tested. Any non-empty string is true, while an empty string is false.
Equal (==)
If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible; else if either operand is a string, the other operand is converted to a string if possible. If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.
(From Comparison Operators in Mozilla Developer Network)
It's according to spec.
12.5 The if Statement
.....
2. If ToBoolean(GetValue(exprRef)) is true, then
a. Return the result of evaluating the first Statement.
3. Else,
....
ToBoolean, according to the spec, is
The abstract operation ToBoolean converts its argument to a value of type Boolean according to Table 11:
And that table says this about strings:
The result is false if the argument is the empty String (its length is zero);
otherwise the result is true
Now, to explain why "0" == false you should read the equality operator, which states it gets its value from the abstract operation GetValue(lref) matches the same for the right-side.
Which describes this relevant part as:
if IsPropertyReference(V), then
a. If HasPrimitiveBase(V) is false, then let get be the [[Get]] internal method of base, otherwise let get
be the special [[Get]] internal method defined below.
b. Return the result of calling the get internal method using base as its this value, and passing
GetReferencedName(V) for the argument
Or in other words, a string has a primitive base, which calls back the internal get method and ends up looking false.
If you want to evaluate things using the GetValue operation use ==, if you want to evaluate using the ToBoolean, use === (also known as the "strict" equality operator)
It's PHP where the string "0" is falsy (false-when-used-in-boolean-context). In JavaScript, all non-empty strings are truthy.
The trick is that == against a boolean doesn't evaluate in a boolean context, it converts to number, and in the case of strings that's done by parsing as decimal. So you get Number 0 instead of the truthiness boolean true.
This is a really poor bit of language design and it's one of the reasons we try not to use the unfortunate == operator. Use === instead.
// I usually do this:
x = "0" ;
if (!!+x) console.log('I am true');
else console.log('I am false');
// Essentially converting string to integer and then boolean.
Your quotes around the 0 make it a string, which is evaluated as true.
Remove the quotes and it should work.
if (0) console.log("ha")
It is all because of the ECMA specs ... "0" == false because of the rules specified here http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.3 ...And if ('0') evaluates to true because of the rules specified here http://ecma262-5.com/ELS5_HTML.htm#Section_12.5
== Equality operator evaluates the arguments after converting them to numbers.
So string zero "0" is converted to Number data type and boolean false is converted to Number 0.
So
"0" == false // true
Same applies to `
false == "0" //true
=== Strict equality check evaluates the arguments with the original data type
"0" === false // false, because "0" is a string and false is boolean
Same applies to
false === "0" // false
In
if("0") console.log("ha");
The String "0" is not comparing with any arguments, and string is a true value until or unless it is compared with any arguments.
It is exactly like
if(true) console.log("ha");
But
if (0) console.log("ha"); // empty console line, because 0 is false
`
This is because JavaScript uses type coercion in Boolean contexts and your code
if ("0")
will be coerced to true in boolean contexts.
There are other truthy values in Javascript which will be coerced to true in boolean contexts, and thus execute the if block are:-
if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)
This is the reason why you should whenever possible use strict equality === or strict inequality !==
"100" == 100
true because this only checks value, not the data type
"100" === 100
false this checks value and data type
The "if" expression tests for truthiness, while the double-equal tests for type-independent equivalency. A string is always truthy, as others here have pointed out. If the double-equal were testing both of its operands for truthiness and then comparing the results, then you'd get the outcome you were intuitively assuming, i.e. ("0" == true) === true. As Doug Crockford says in his excellent JavaScript: the Good Parts, "the rules by which [== coerces the types of its operands] are complicated and unmemorable.... The lack of transitivity is alarming." It suffices to say that one of the operands is type-coerced to match the other, and that "0" ends up being interpreted as a numeric zero, which is in turn equivalent to false when coerced to boolean (or false is equivalent to zero when coerced to a number).
if (x)
coerces x using JavaScript's internal toBoolean (http://es5.github.com/#x9.2)
x == false
coerces both sides using internal toNumber coercion (http://es5.github.com/#x9.3) or toPrimitive for objects (http://es5.github.com/#x9.1)
For full details see http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
I have same issue, I found a working solution as below:
The reason is
if (0) means false, if (-1, or any other number than 0) means true. following value are not truthy, null, undefined, 0, ""empty string, false, NaN
never use number type like id as
if (id) {}
for id type with possible value 0, we can not use if (id) {}, because if (0) will means false, invalid, which we want it means valid as true id number.
So for id type, we must use following:
if ((Id !== undefined) && (Id !== null) && (Id !== "")){
} else {
}
for other string type, we can use if (string) {}, because null, undefined, empty string all will evaluate at false, which is correct.
if (string_type_variable) { }
In JS "==" sign does not check the type of variable. Therefore, "0" = 0 = false (in JS 0 = false) and will return true in this case, but if you use "===" the result will be false.
When you use "if", it will be "false" in the following case:
[0, false, '', null, undefined, NaN] // null = undefined, 0 = false
So
if("0") = if( ("0" !== 0) && ("0" !== false) && ("0" !== "") && ("0" !== null) && ("0" !== undefined) && ("0" !== NaN) )
= if(true && true && true && true && true && true)
= if(true)
I came here from search looking for a solution to evaluating "0" as a boolean.
The technicalities are explained above so I won't go into it but I found a quick type cast solves it.
So if anyone else like me is looking to evaluate a string 1 or 0 as boolean much like PHP. Then you could do some of the above or you could use parseInt() like:
x = "0";
if(parseInt(x))
//false

Categories

Resources