The result of []==false is true, why? [duplicate] - javascript

I have two statements like this. Why do they both evaluate to false?
console.log([] == true)
console.log(![] == true)
If [] == true is false shouldn't ![] == true result to true?

It's the way coercion works.
The first step of coercion is to convert any non primitive types to primitive types, then using a set of rules convert the left, right or both sides to the same type. You can find these rules here.
In your case [] == true, would pass through these 4 steps:
[] == true
[] == 1
"" == 1
0 == 1
Whereas based on operator precedence the ! in ![] == true is executed first so the expression is converted to false == true which is obviously false.
You can try the live demo by Felix Kling to better understand how the sameness operator works.
In more words:
The value ![] is false, because [] is an Object (arrays are objects) and all objects, not including null, are truthy. So any array, even if it is empty will always be a truthy, and the opposite of a truthy is always false. The easiest way to check if a value is a truthy is by using !!.
console.log("![]: " + ![]);
console.log("!![]: " + !![]);
When you are using a loose comparison (using == instead of ===) you are asking the JavaScript engine to first convert the values into the same type and then compare them. So what happens is the values get converted according to a set of rules, once they are the same type, they get compared though the same process as a strict equality check (===). The first change that [] goes through is to get converted to a string, the string version of an empty array is an empty string "", the empty string is then converted to a number, the numeric value of an empty string is 0, since the numeric value of true is 1 and 0 != 1, the final output is false.
console.log("[] == true => `" + ([] == true) + "`");
console.log("String([]) => `" + String([]) + "`");
console.log("Number('') => `" + Number("") + "`");
console.log("Number(true) => `" + Number(true) + "`");

As per the Abstract Equality Comparison Algorithm - http://es5.github.io/#x11.9.3
Types of x and y are checked when x == y is to be checked.
If no rule matches, a false is returned.
For [] == true , rule 7 matches, so a result of [] == ToNumber(true) is returned i.e. false is returned.
Reason you're getting the same result for ![] == true, because ![] returns false, and false == true returns false .
To get opposite result for your second operation, add a precedence (i.e. wrap) to your expression with braces.
console.log(!([] == true)); // returns true

Put ![] in the console. It's false.
So ![] == true is the same as false == true, which is false.
[] != true is true though

None of the answers so far has addressed the main problem. [Edit: This is no longer true. See Nick Zoum's answer.]
The question essentially is this:
[] == true returns false
=> [] is not true
=> [] is false (because something not true must be false)
=> ![] should be true, since negation of false is true. Then why does ![] == true return false?
[] is actually truthy. (So ![] is actually falsy.)
Still, [] == true returns false -- the reason is coercion. It's another of Javascript's gotchas.
When an array is checked for equality explicitly against a boolean value (that is, against true or false), its elements are first converted to strings and then joined together. An empty array therefore becomes "" — therein lies the problem, because an empty string is falsy.
In brief, an empty array is truthy, but it's coerced (when being compared to a boolean value) to an empty string, which is falsy.
Note the following, which comes from https://www.nfriedly.com/techblog/2009/07/advanced-javascript-operators-and-truthy-falsy/
Arrays are particularly weird. If you just test it for truthyness, an
empty array is truthy. HOWEVER, if you compare an empty array to a
boolean, it becomes falsy:
if ( [] == false ) {
// this code runs }
if ( [] ) {
// this code also runs }
if ([] == true) {
// this code doesn't run }
if ( ![] ) {
// this code also doesn't run }
(This is because when you do a comparison, its elements are turned to Strings and joined. Since it's empty, it becomes "" which is then falsy. Yea, it's weird.)

Read https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
Rule in JavaScript for The Equals Operator (==)
if
type(x) type(y) result
1.x and y are the same type See Strict Equality (===) Algorithm
2.null Undefined true
3.Undefined null true
4. Number String x == toNumber(y)
5. String Number toNumber(x) == y
6. Boolean (any) toNumber(x) == y
7. (any) Boolean x == toNumber(y)
8.String or Number Object x == toPrimitive(y)
9.Object String or Number toPrimitive(x) == y
***10.otherwise… false

Related

Why do both "[] == true" and "![] == true" evaluate to false?

I have two statements like this. Why do they both evaluate to false?
console.log([] == true)
console.log(![] == true)
If [] == true is false shouldn't ![] == true result to true?
It's the way coercion works.
The first step of coercion is to convert any non primitive types to primitive types, then using a set of rules convert the left, right or both sides to the same type. You can find these rules here.
In your case [] == true, would pass through these 4 steps:
[] == true
[] == 1
"" == 1
0 == 1
Whereas based on operator precedence the ! in ![] == true is executed first so the expression is converted to false == true which is obviously false.
You can try the live demo by Felix Kling to better understand how the sameness operator works.
In more words:
The value ![] is false, because [] is an Object (arrays are objects) and all objects, not including null, are truthy. So any array, even if it is empty will always be a truthy, and the opposite of a truthy is always false. The easiest way to check if a value is a truthy is by using !!.
console.log("![]: " + ![]);
console.log("!![]: " + !![]);
When you are using a loose comparison (using == instead of ===) you are asking the JavaScript engine to first convert the values into the same type and then compare them. So what happens is the values get converted according to a set of rules, once they are the same type, they get compared though the same process as a strict equality check (===). The first change that [] goes through is to get converted to a string, the string version of an empty array is an empty string "", the empty string is then converted to a number, the numeric value of an empty string is 0, since the numeric value of true is 1 and 0 != 1, the final output is false.
console.log("[] == true => `" + ([] == true) + "`");
console.log("String([]) => `" + String([]) + "`");
console.log("Number('') => `" + Number("") + "`");
console.log("Number(true) => `" + Number(true) + "`");
As per the Abstract Equality Comparison Algorithm - http://es5.github.io/#x11.9.3
Types of x and y are checked when x == y is to be checked.
If no rule matches, a false is returned.
For [] == true , rule 7 matches, so a result of [] == ToNumber(true) is returned i.e. false is returned.
Reason you're getting the same result for ![] == true, because ![] returns false, and false == true returns false .
To get opposite result for your second operation, add a precedence (i.e. wrap) to your expression with braces.
console.log(!([] == true)); // returns true
Put ![] in the console. It's false.
So ![] == true is the same as false == true, which is false.
[] != true is true though
None of the answers so far has addressed the main problem. [Edit: This is no longer true. See Nick Zoum's answer.]
The question essentially is this:
[] == true returns false
=> [] is not true
=> [] is false (because something not true must be false)
=> ![] should be true, since negation of false is true. Then why does ![] == true return false?
[] is actually truthy. (So ![] is actually falsy.)
Still, [] == true returns false -- the reason is coercion. It's another of Javascript's gotchas.
When an array is checked for equality explicitly against a boolean value (that is, against true or false), its elements are first converted to strings and then joined together. An empty array therefore becomes "" — therein lies the problem, because an empty string is falsy.
In brief, an empty array is truthy, but it's coerced (when being compared to a boolean value) to an empty string, which is falsy.
Note the following, which comes from https://www.nfriedly.com/techblog/2009/07/advanced-javascript-operators-and-truthy-falsy/
Arrays are particularly weird. If you just test it for truthyness, an
empty array is truthy. HOWEVER, if you compare an empty array to a
boolean, it becomes falsy:
if ( [] == false ) {
// this code runs }
if ( [] ) {
// this code also runs }
if ([] == true) {
// this code doesn't run }
if ( ![] ) {
// this code also doesn't run }
(This is because when you do a comparison, its elements are turned to Strings and joined. Since it's empty, it becomes "" which is then falsy. Yea, it's weird.)
Read https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/
Rule in JavaScript for The Equals Operator (==)
if
type(x) type(y) result
1.x and y are the same type See Strict Equality (===) Algorithm
2.null Undefined true
3.Undefined null true
4. Number String x == toNumber(y)
5. String Number toNumber(x) == y
6. Boolean (any) toNumber(x) == y
7. (any) Boolean x == toNumber(y)
8.String or Number Object x == toPrimitive(y)
9.Object String or Number toPrimitive(x) == y
***10.otherwise… false

Why (!a) and (a == false) are not equal?

Talk is cheap, I will show my code.
var a; // a = undefined
if(a == false){ // As I typed == not ===, a needs to be translated to boolean (undefined == false) but it doesn't
return false;
}
else {
return true;
}
// true
This returns true but I was sure that it would return false because undefined is the same as false when I'm using double equal.
Things came strange when I tried to use
if(!a){..} else {..};
// false
Here I got my false but till this moment I thought (!a) and (a == false) are absolutely equals.
The short answer:
!a converts a value to a Boolean.
a == false compares a value to a Boolean.
These are two different operations.
!a is equivalent to Boolean(a) ? false : true. Boolean(a) returns false if a is
undefined
null
0
''
NaN
false
In every other case it returns true.
What happens in a == false is a bit more evolved, but not that complicated. The most important thing that happens is that false is converted to a number, so you are actually comparing a == 0. But undefined is treated in a special way in the comparison algorithm. It's not converted to any other type, so the algorithm simply returns false.
I wrote the following interactive tool for a JavaScript course which shows you which steps of the algorithm are performed when comparing two values:
Similar questions:
In JavaScript, why is "0" equal to false, but when tested by 'if' it is not false by itself?
Why does ('0' ? 'a' : 'b') behave different than ('0' == true ? 'a' : 'b')
JavaScript: What is the difference between `if (!x)` and `if (x == null)`?
Why "" == "0" is false in javascript?
The only correct answer is "that's the way it is". The source of your confusion is a feature of JavaScript called type coercion and different types of equality comprisons (==, === in JavaScript).
There's an interesting table which tells you which comparisons will result to true on JavaScript Equality Table.
The only two values which will give true when ==-compared with null are null and undefined.
In other words, x == null will be true if and only if x is null or undefined.
You had a false assumption. x == false does not coerect x to boolean. In fact, == has it's own equality table.
If you don't believe random blogposts, here is the spec:
7.2.12 Abstract Equality Comparison
The comparison x == y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
ReturnIfAbrupt(x).
ReturnIfAbrupt(y).
If Type(x) is the same as Type(y), then Return the result of performing Strict Equality Comparison x === y.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String, Number, or Symbol and Type(y) is Object, then return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String, Number, or Symbol, then return the result of the comparison ToPrimitive(x) == y.
Return false.
So for undefined == false: first we hit #9, and then #12, which evaluates to false.
(!a) and (a == false) are absolutely equals.
you use two different operators and assume they are absolutely equals - never do this, there is a reason 2 different operators exists instead of 1.
Now, think of NaN (as one example, others may apply). By definition NaN is a falsy value but not false value, so:
if(!NaN) {} // this will execute
if(NaN == false) {} // this will not execute
Why do you think this happens?
Because == operator does type coercion per type/value, thus NaN doesn't coerce to false, while others, like 0 may, but both will be considered falsy and converted to true using !
Summed:
operator ! uses a defined set of falsy values (false,0, '' or "" (empty string), null, undefined, NaN) all else is truthy
operator == uses per type conversions not regarding if the original value is considered falsy, so after being converted, it may well be truthy

If an array is truthy in JavaScript, why doesn't it equal true?

I have the following code snippet:
if([]) {
console.log("first is true");
}
The console says first is true which means [] is true. Now I am wondering why this:
if([] == true) {
console.log("second is true");
}
and this:
if([] === true) {
console.log("third is true");
}
are not true. If the console logged first is true in the first snippet, that means [] should be true, right? So why do the latter two comparisons fail? Here is the fiddle.
This is by specification. By the ECMAScript 2015 Language Specification, any object that is implicitly coerced into a boolean is true; that means objects are truthy. Inside of an if statement, the condition, once evaluated and if not already boolean, is coerced into a boolean. Thus, doing:
if([]) {
...
}
[] is truthy when coerced to a boolean and is true.
On the other hand, when you try to compare two values of differing types with abstract comparison, ==, the engine must internally go through an algorithm to reduce the values to similar types, and ultimately integers that it can compare. In Section 7.2.12 of the specification on the steps for Abstract Equality Comparison x == y, it states:
7.2.12 Abstract Equality Comparison
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
[...]
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
Thus, the y operand (in this case true) is converted to 1 by coercion with ToNumber since it is a boolean, and [] == 1 is false because:
If Type(x) is Object and Type(y) is either String, Number, or Symbol, then
return the result of the comparison ToPrimitive(x) == y.
This will convert the x operand to a string with the toString method of the array, which is "" for an empty array in this case. After going through ToPrimitive, it will result in:
if("" == 1) {
...
}
And finally:
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
Thus, ToNumber of an empty string "" is 0 and you get:
if(0 == 1) {
...
}
And 0 does not equal 1, thus it is false. Remember that just because something is truthy, does not make it equal to true. Just try Symbol() == true or ({}) == true.
The final comparison, with === is strict comparison, and does not coerce any operands and will return false if both operands are not the same type. Since the left operand is an object (an array) and the right is a number, the comparison evaluates to false.
You have force type coercion before making a Boolean equity check with the Object types.
while "" == false // <- true or 0 == false // <- true works out well
with the Object types it doesn't
null == false // <- false
so you better do like
!!null === false // <- true or !![] === true // <- true
This is strict equality. It meas that both operands should be the same thing. In the case of object, they should be exactly the same object. Comparison between object with the same structure and the same values will fail, they need to be reference to the same object to success.
if([]===true){
console.log("third is true");
}
In case of operands of different types, than the comparison between them becomes strict. This leads to the case above.
if([]==true){
console.log("second is true");
}
Also, in the first if statement, [] is automatically casted to boolean true.
Boolean([]) is trying to ascertain whether the operand is truthy or not. Similarly, if([]) console.log('truthy') is checking whether the expression is truthy or not.
However, true == [] does not immediately decide to check truthiness. Instead, it follows the == weak equality checking rules.
The rule for true == [] is:
If one of the operands is an object and the other is a primitive,
convert the object to a primitive.
Objects (including arrays) are converted into primitives by calling the ##toPrimitive method on the object. This method does not exist on regular arrays and objects, but will exist if you add it to an object or declare it as a method of the class of an object.
During the weak equality type coercion, the hint sent to the ##toPrimitive method is 'default'. However, in other situations, a different hint is provided, allowing the object to coerce to different primitives in different situations.
const a = []
const b = []
b[Symbol.toPrimitive] = function (hint) {
if(hint==='number') return 3;
if(hint==='string') return 'hello'
else return false; // happens when hint is 'default'
}
const log = x=>console.log(x)
log(a==true) // false - a has no toPrimitive function
log(a==false) // false - a has no toPrimitive function
log(b==true) // false - toPrimitive returns false
log(b==false) // true - toPrimitive returns false
log(!b) // false - checks for truthiness, and objects are truthy
log(Boolean(b)) // true - checks for truthiness, and objects are truthy
log(b==3) // false - toPrimitive with hint=default returns false
log(Number(b)) // 3 - toPrimitive with hint=number returns 3
log(b=='hello') // false - toPrimitive with hint=default returns false
log(String(b)) // 'hello' - toPrimitive with hint=string returns 'hello'
log(+b) // 3 - `+` calls toPrimitive with hint=number,
// which returns 3
log(b+"") // 'false' - toPrimitive with hint=default returns false
log(`${b}`) // 'hello' - template literals call toPrimitive with
// hint=string, which returns 'hello'

JavaScript transitive equality

Learning JavaScript and found that given the expression below, it evaluates to true when given this: transitive([1], 1, {toString:_=>'1'});
I don't understand why.
it makes sense that the y and z are equal but how can the x and y be equal if the x and z are not equal?
function transitive(x,y,z) {
return x && x == y && y == z && x != z;
}
In JavaScript there is a concept of "truthiness" and "falsyness". Values like 1 and '1' are equal when compared with a loose comparison operator like ==, but are not strictly equal using a strict equality operator like ===.
The object is equal to 1 because JavaScript uses type coercion to convert the object to a comparable value to a primitive. It does this by calling the .toString() method of the object, which returns '1' and as we learned above is truthy, as is 1, so they are considered equal when using ==.
This will probably be relevant: MDN: Equality comparisons and sameness.
It is best/common practice in JavaScript to always use === and !== in place of == and !=.
The "loose" equality operator in javascript (==) is not transitive. This is primarily a result of type coercion that occurs before comparison. == uses javascript's "abstract equality" algorithm which roughly boils down to these steps. Successive coercions can occur.
If one operand is a primitive and another is an object (including an array), a not so simple algorithm is used to coerce the object to a primitive, which can involve (among other things) the object's toString, valueOf, or [Symbol.toPrimitive] method.
Booleans are coerced to numbers.
If one operand is a number and the other is a string, the string is coerced to a number.
null and undefined are considered equal to themselves and eachother and nothing else. Otherwise a strict equality comparison is performed.
That's a lot of complexity packed into a single operator and the result is a very wiggly concept of equality with a bunch of gotchas.
// Is an empty array truthy or falsey?
[] == false; // -> true, so [] is falsey?
[] ? true : false; // -> true, so [] is truthy?
// Another case of intransitivity:
false == "0" // -> true
false == [] // -> true
"0" == [] // -> false
// Not super consistent
123 == "123" // -> true
123 == [123] // -> true
true == "true" // -> false
true == [true] // -> false
"true" == [true] // -> true
true == ["1"] // -> true
Applying these coercion rules to your example:
[1] == 1
// Object is coerced to primitive, in this case via toString
"1" == 1
// String is coerced to number
1 == 1
/* true */
1 == {toString:_=>'1'}
// Object is coerced to primitive, in this case via toString
1 == "1"
// String is coerced to number
1 == 1
/* true */
[1] == {toString:_=>'1'}
// Since neither value is a primitive, no coercion occurs.
// Reference equality is checked instead.
/* false */
Just about the only reason I use == is to check if a value is either null or undefined with a single comparison. Otherwise I stick with === which is much easier to reason about.

How does Type Coercion in Javascript in the case of object to boolean?

To the best of my knowledge, (x == false) should do the same thing as !x, as both of them try to interpret x as a boolean, and then negates it.
However, when I tried to test this out, I started getting some extremely strange behavior.
For example:
false == [] and false == ![] both return true.
Additionally
false == undefined and true == undefined both return false, as does
false == Infinity and true == Infinity and
false == NaN and true == NaN.
What exactly is going on here?
http://jsfiddle.net/AA6np/1/
It's all here: http://es5.github.com/#x11.9.3
For the case of false == []:
false is converted to a number (0), because that is always done with booleans.
[] is converted to a primitive by calling [].valueOf().toString(), and that is an empty string.
0 == "" is then evaluated by converting the empty string to a number, and because the result of that is also 0, false == [] is true.
For the case of false == ![]:
The logical not operator ! is performed by returning the opposite of ToBoolean(GetValue(expr))
ToBoolean() is always true for any object, so ![] evaluates to false (because !true = false), and therefore is false == ![] also true.
(false == undefined) === false and (true == undefined) === false is even simpler:
false and true are again converted to numbers (0 and 1, respectively).
Because undefined cannot be compared to a number, the chain bubbles through to the default result and that is false.
The other two cases are evaluated the same way: First Boolean to Number, and then compare this to the other number. Since neither 0 nor 1 equals Infinity or is Not A Number, those expressions also evaluate to false.
The abstract equality algorithm is described in section 9.3 of the specification.
For x == y where x = false and y = []:
Nope. Types are not equal.
Nope, x is not null.
Nope. x is not undefined.
Nope, x is not a number
Nope, x is not a string.
Yes, x is a boolean, so we compare ToNumber(x) and y.
Repeat the algorithm, x=0 and y=[].
We end at step 8:Type(x) == number. and Type(y) == object.
So, let the result be x == ToPrimitive(y).
ToPrimitive([]) == ""
Now, repeat the algorithm again with x=0 and y="". We end at 4: "return the result of the comparison x == ToNumber(y)."
ToNumber("") == 0
The last repetition of the algorithm ends at step 1 (types are equal). By 1.c.iii, 0 == 0, and true is returned.
The other results can be obtained in a similar manner, by using the algorithm.
false == []
Using == Javascript is allowed to apply conversions. The object will convert into a primitive to match type with the boolean, leaving an empty string. The false will convert into a number 0. The compares the empty string and the number 0. The string is converted to a number which will be 0, so the expression is "true"
![]
Javascript converts the object to the boolean true, therefore denying true ends being false.
false == undefined true == undefined
false == Infinity and true == Infinity
false == NaN and true == NaN
Again a bit of the same! false is converted to 0, true to 1. And then, undefined is converted to a number which is... NaN! So false in any case
I would recommend to use === !== as much as you can to get "expected" results unless you know very well what you are doing. Using something like Boolean(undefined) == false would also be nice.
Check ECMAScript specifications for all the details when converting stuff.

Categories

Resources