Transitivity in javascript - javascript

In mathematics, = is assumed to be a transitive relationship. Transitivity means precisely what you stated: A = B and B = C implies A = C.But, from what I can see, javascript does not respect this transitivity principle.
For all of the below expressions, the output is TRUE
[]==0
true
0==[]
true
"0" == 0
true
0 == "0"
true
But, this is false
"0" == []
false
What is the reason behind it, and how compiler treat this expression?

Check out this documentation on the non-strict Javascript equality operator. It attempts to convert objects which do not have the same type, and while it apparently supports [] and 0, it does not have coercion for "0" and [].
My guess at the reasoning behind this: 0 is commonly used to represent the Boolean value of False. [] has a value of False when converted to Boolean, so it is expedient to say that [] == 0 in Boolean terms. "0" == 0, however, is true for a different reason; the string "0" represents the integer 0. In logical terms, the equality operator is actually representing two different relations, so transitivity does not hold between them.

The right-hand value is being coerced to a string.
console.log("0" == []) // false
console.log([].toString()) // ""
console.log("" == [].toString()) // true
console.log("0" == [0].toString()) // true
console.log([0, 1, 2, 3].toString()) // 0,1,2,3
console.log("0,1,2,3" == [0, 1, 2, 3]) // true

JavaScript's aggressive type of coercion leads to odd results. The string equivalent of an empty array is an empty string, so that is why it works.
As well, converting an empty string to a number gives zero, so you can also convert Array to Number.
The string "0" is equal to 0 because calling 0.toString gives "0".
But we said earlier that an empty array becomes an empty string, so we can't have "0" as a converted version of an empty array.
All this happens in the first place due to "==", which coerces types. With "===", none of these equalities are true.

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 does (true > null) always return true in JavaScript?

Can some tell me why the following code returns true in JavaScript?
console.log(true > null); //returns true
null is like false in this case, wich is 0 as a number. true is 1 as a number.
1 is bigger (>) than 0.
They are converted to numbers, null gives 0 and true gives 1
http://ecma-international.org/ecma-262/5.1/#sec-11.8.5
If it is not the case that both Type(px) is String and
Type(py) is String, then
Let nx be the result of calling ToNumber(px). Because px and py
are primitive values evaluation order is not important.
Let ny be the result of calling ToNumber(py).
Number(null) //0
Number(true) //1
May be because true = 1 where null = 0
JavaScript does a lot of type coercion in the background and a lot of the results you'll find aren't useful (see http://wtfjs.com/).
In this case, true which is coerced as 1 is greater than null which is coerced to 0. Since 1 is greater than 0 the result is true.
If one of the operands is Boolean, the Boolean operand is converted to
1 if it is true and +0 if it is false.
From the MDN.
What's happening behind is that the relational operators ( > in this case) perform type coercion before doing the comparison. When doing the ToPrimitive, true gets coerced to a 1, and null to a 0.
You can check details here of how the operators actually work here
The code is incorrect, you need to do:
console.log(true > typeof null);
The compare operator ">" forces both it's left and right side to be converted to numbers.
Number(true) is 1, Number(null) is 0, so what is in the paranthesis is taken as "1>0", which is always true in result.

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

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

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.

Categories

Resources