I recently discovered that 2 == [2] in JavaScript. As it turns out, this quirk has a couple of interesting consequences:
var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true
Similarly, the following works:
var a = { "abc" : 1 };
a[["abc"]] === a["abc"]; // this is also true
Even stranger still, this works as well:
[[[[[[[2]]]]]]] == 2; // this is true too! WTF?
These behaviors seem consistent across all browsers.
Any idea why this is a language feature?
Here are more insane consequences of this "feature":
[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!
var a = [0];
a == a // true
a == !a // also true, WTF?
You can look up the comparison algorithm in the ECMA-spec (relevant sections of ECMA-262, 3rd edition for your problem: 11.9.3, 9.1, 8.6.2.6).
If you translate the involved abstract algorithms back to JS, what happens when evaluating 2 == [2] is basically this:
2 === Number([2].valueOf().toString())
where valueOf() for arrays returns the array itself and the string-representation of a one-element array is the string representation of the single element.
This also explains the third example as [[[[[[[2]]]]]]].toString() is still just the string 2.
As you can see, there's quite a lot of behind-the-scene magic involved, which is why I generally only use the strict equality operator ===.
The first and second example are easier to follow as property names are always strings, so
a[[2]]
is equivalent to
a[[2].toString()]
which is just
a["2"]
Keep in mind that even numeric keys are treated as property names (ie strings) before any array-magic happens.
It is because of the implicit type conversion of == operator.
[2] is converted to Number is 2 when compared with a Number. Try the unary + operator on [2].
> +[2]
2
var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true
On the right side of the equation, we have the a[2], which returns a number type with value 2. On the left, we are first creating a new array with a single object of 2. Then we are calling a[(array is in here)]. I am not sure if this evaluates to a string or a number. 2, or "2". Lets take the string case first. I believe a["2"] would create a new variable and return null. null !== 2. So lets assume it is actually implicitly converting to a number. a[2] would return 2. 2 and 2 match in type (so === works) and value. I think it is implicitly converting the array to a number because a[value] expects a string or number. It looks like number takes higher precedence.
On a side note, I wonder who determines that precedence. Is because [2] has a number as it's first item, so it converts to a number? Or is it that when passing an array into a[array] it tries to turn the array into a number first, then string. Who knows?
var a = { "abc" : 1 };
a[["abc"]] === a["abc"];
In this example, you are creating an object called a with a member called abc. The right side of the equation is pretty simple; it is equivalent to a.abc. This returns 1. The left side first creates a literal array of ["abc"]. You then search for a variable on the a object by passing in the newly created array. Since this expects a string, it converts the array into a string. This now evaluates to a["abc"], which equals 1. 1 and 1 are the same type (which is why === works) and equal value.
[[[[[[[2]]]]]]] == 2;
This is just an implicit conversion. === wouldn't work in this situation because there is a type mismatch.
For the == case, this is why Doug Crockford recommends always using ===. It doesn't do any implicit type conversion.
For the examples with ===, the implicit type conversion is done before the equality operator is called.
[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!
That's interesting, it's not that [0] is both true and false, actually
[0] == true // false
It is javascript's funny way of processing if() operator.
A array of one item can be treated as the item itself.
This is due to duck typing. Since "2" == 2 == [2] and possibly more.
To add a little detail to the other answers... when comparing an Array to a Number, Javascript will convert the Array with parseFloat(array). You can try it yourself in the console (eg Firebug or Web Inspector) to see what different Array values get converted to.
parseFloat([2]); // 2
parseFloat([2, 3]); // 2
parseFloat(['', 2]); // NaN
For Arrays, parseFloat performs the operation on the Array's first member, and discards the rest.
Edit: Per Christoph's details, it may be that it is using the longer form internally, but the results are consistently identical to parseFloat, so you can always use parseFloat(array) as shorthand to know for sure how it will be converted.
You are comparing 2 objects in every case.. Dont use ==, if you are thinking of comparison, you are having === in mind and not ==. == can often give insane effects. Look for the good parts in the language :)
Explanation for the EDIT section of the question:
1st Example
[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!
First typecast [0] to a primitive value as per Christoph's answer above we have "0" ([0].valueOf().toString())
"0" == false
Now, typecast Boolean(false) to Number and then String("0") to Number
Number("0") == Number(false)
or 0 == 0
so, [0] == false // true
As for if statement, if there is not an explicit comparison in the if condition itself, the condition evaluates for truthy values.
There are only 6 falsy values: false, null, undefined, 0, NaN and empty string "". And anything that is not a falsy value is a truthy value.
Since [0] is not a falsy value, it is a truthy value, the if statement evaluates to true & executes the statement.
2nd Example
var a = [0];
a == a // true
a == !a // also true, WTF?
Again type casting the values to primitive,
a = a
or [0].valueOf().toString() == [0].valueOf().toString()
or "0" == "0" // true; same type, same value
a == !a
or [0].valueOf().toString() == [0].valueOf().toString()
or "0" == !"0"
or "0" == false
or Number("0") == Number(false)
or 0 = 0 // true
Related
This question already has answers here:
[] == ![] evaluates to true
(5 answers)
Closed 4 years ago.
var arr = [];
Boolean(arr) // true
Boolean(!arr) // false
arr == arr // true
arr == !arr // true ??? what ???
I do not want to get the answer that 'recommend using === instead of =='.
I would like to know the reason for this phenomenon and the principle of type conversion of JavaScript.
Type conversion in JS, particularly with regards to loose equality, is a tricky beast.
The best place to always start when answering the question "why does this particular loose equality evaluate this way" is to consult this table of equality comparisons by operand type.
In this case, we can see that for [] == false, Operand A is an Object and Operand B is a Boolean, so the actual comparison performed is going to be ToPrimitive(A) == ToNumber(B).
The right side of that is simple; ToNumber(false) evaluates to 0. Done and done.
The left side is more complex; you can check the official ECMAScript spec for full documentation of ToPrimitive, but all you really need to know is that in this case it boils down to A.valueOf().toString(), which in the case of the empty array is simply the empty string ""
So, we end up evaluating the equality "" == 0. A String/Number == comparison performs ToNumber on the string, and ToNumber("") is 0, so we get 0 == 0, which is of course true.
Double equals, ==, performs an amount of type coercion on values before attempting to check for equality.
So arr == arr returns true as you'd expect as what you are actually checking is if [] == [] and both sides of the equation are of the same type.
arr == !arr is actually checking if [] == false. The == then performs type coercion on the [] value. This does not, as Hamms pointed out, perform a boolean conversion, instead [] is turned into a primitive, which is an empty string due to reasons. So now our equation is '' == false. The types on the two sides of this operation are still not the same. So the type coercion kicks in again, and due to truthy and falsey values in javascript, '' also evaluates to false. The equation now becomes false == false, which is obviously true.
This question already has answers here:
Why is `[] == false` is true but just `[]` evaluates to true? [duplicate]
(4 answers)
Closed 8 years ago.
I'm trying to figure out why JavaScript has this strange behaviour in comparing the same array:
var array = [0];
console.log(array == array); //true
console.log(array == !array); //true?
The first one is easily done, they are referencing the same object, but the second is a really tricky one, and I'm working on understanding the process.
Please note that I'm aware that this is abstract equality comparison and not strict equality comparison, and I know their differences (I know that using === would lead to false result, but I'm trying to figure out the behaviour with ==).
P.s.: this one was taken from wtfjs.com, and I didn't find out the explanation, so I tried to give it myself and thought it could be "useful".
The first equality is simple, it's a comparison between the same object (same reference), so it returns true.
The second one is a bit tricky, so I'll try to explain better below.
TL;DR
For those who are a bit lazy, here is a simple explanation without quoting the spec every step:
[0] == ![0] => we evaluate ![0] first, which yields false(because [0] is a truthy value).
[0] == false => [0] is evaluated to [0].toString() which is "0".
"0" == false => "0" is converted to the number 0; the same is for false, so we obtain:
0 == 0 which is finally true.
Complete explanation
As for the first equality, for the sake of completeness, I quote here the interested part of the spec.
1.f Return true if x and y refer to the same object. Otherwise, return false.
So this returns true, as expected. Now the tricky part:
First of all, we have to evaluate the UnaryExpression on the right:
Let expr be the result of evaluating UnaryExpression.
Let oldValue be ToBoolean (GetValue(expr) ).
If oldValue is true, return false.
Return true.
But ToBoolean uses this algorithm, and GetValue should return either an Object or a non-empty String, so the result of the evaluation is true. Returning to our UnaryExpression, we have !true, so the result of the final evaluation is false.
So we're back at our original comparison, now we are comparing an Object against a Boolean.
7.If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
ToNumber(false) is 0, so now we are comparing Object and Number.
Back to the specs:
9.If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
Calling ToPrimitive on our array should return its [[DefaultValue]], which should be, according to this kangax's answer, the result of calling toString on the array itself, so we obtain "0".
So, back to our comparison, it has became an equality between a String and a Number.
5.If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
Calling ToNumber on our string "0" yields 0, again we are finally at a simple comparison: 0 == 0.
Final spec step:
1.c.iii If x is the same Number value as y, return true.
And here the result explained.
The algorithm for the == operator evaluates the expressions from left to right, so given:
var array = [0];
and evaluating:
array == !array;
then first the left hand expression is evaluated and an array is returned. Then the right hand expression is evaluated: ToBoolean is applied to array and, since it's an object, it returns true and the ! operator reverses that to false.
Then the abstract equailty comparison algorithm is used. Again, the left hand side is evaluated first. Since array is an Object and not a Boolean, String or Number, step 7 is used and the right hand side is converted to a Number and the comparison becomes:
array == 0;
The algorithm is run again and gets to step 9, where array is converted to a primitive (string in this case) and the comparison becomes:
'0' == 0;
The algorithm is run again and gets to step 5 where the left hand side is converted to a Number and the comparison becomes:
0 == 0;
The algorithm is run again and this time the expressions have the same Type (Number) so step 1.iii.c is used to return true.
Please note that through all of this, the left hand side is always evaluated first, though sometimes that results in the right hand side being modified and not the left (e.g. at step 7 of the algorithm).
I was encountering a lot of bugs in my code because I expected this expression:
Boolean([]); to evaluate to false.
But this wasn't the case as it evaluated to true.
Therefore, functions that possibly returned [] like this:
// Where myCollection possibly returned [ obj1, obj2, obj3] or []
if(myCollection)
{
// ...
}else
{
// ...
}
did not do expected things.
Am I mistaken in assuming that [] an empty array?
Also, Is this behavior consistent in all browsers? Or are there any gotchas there too? I observed this behavior in Goolgle Chrome by the way.
From http://www.sitepoint.com/javascript-truthy-falsy/
The following values are always falsy:
false
0 (zero)
0n (BigInt zero)
"" (empty string)
null
undefined
NaN (a special Number value meaning Not-a-Number!)
All other values are truthy, including "0" (zero in quotes), "false" (false in quotes), empty functions, empty arrays ([]), and empty objects ({}).
Regarding why this is so, I suspect it's because JavaScript arrays are just a particular type of object. Treating arrays specially would require extra overhead to test Array.isArray(). Also, it would probably be confusing if true arrays behaved differently from other array-like objects in this context, while making all array-like objects behave the same would be even more expensive.
You should be checking the .length of that array to see if it contains any elements.
if (myCollection) // always true
if (myCollection.length) // always true when array has elements
if (myCollection.length === 0) // same as is_empty(myCollection)
While [] equals false, it evaluates to true.
yes, this sounds bad or at least a bit confusing. Take a look at this:
const arr = [];
if (arr) console.log("[] is truethy");
if (arr == false) console.log("however, [] == false");
In practice, if you want to check if something is empty,
then check the length. (The ?. operator makes sure that also null is covered.)
const arr = []; // or null;
if (!arr?.length) console.log("empty or null")
[]==false // returns true
This evaluates to true, because of the Abstract Equality Algorithm as mentioned here in the ECMA Specification #Section 11.9.3
If you run through algorithm, mentioned above.
In first iteration, the condition satisfied is,
Step 7: If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
Hence the above condition transforms to -> [] == 0
Now in second iteration, the condition satisfied on [] == 0:
Step 9: If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
[] is an object, henceforth, on converting to primitive, it transforms to an empty string ''
Hence, the above condition transforms to -> '' == 0
In third iteration, condition satisfied, is:
Step 5: If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
As we know, empty string, '' is a falsy value, hence transforming an empty string to number will return us a value 0.
Henceforth, our condition, will transform to -> 0 == 0
In fourth iteration, the first condition is satisfied, where the types are equal and the numbers are equal.
Henceforth, the final value of the [] == false reduces to 0 == 0 which is true.
Hope this answers your question. Otherwise, you can also refer this youtube video
I suspect it has something to do with discrete math and the way a conditional (if then) works. A conditional has two parts, but in the instance where the first part doesn't exist, regardless of the second part, it returns something called a vacuous truth.
Here is the example stated in the wikipedia page for vacuous truths
"The statement "all cell phones in the room are turned off" will be true when no cell phones are in the room. In this case, the statement "all cell phones in the room are turned on" would also be vacuously true"
The wikipedia even makes specific mention of JavaScript a little later.
https://en.wikipedia.org/wiki/Vacuous_truth#:~:text=In%20mathematics%20and%20logic%2C%20a,the%20antecedent%20cannot%20be%20satisfied.&text=One%20example%20of%20such%20a,Eiffel%20Tower%20is%20in%20Bolivia%22.
Also want to add, that all objects in JavaScript (arrays are objects too) are stored in memory as links and these links are always not null or zero, that's why Boolean({}) === true, Boolean([]) === true.
Also this is the reason why same objects (copied by value not the link) are always not equal.
{} == {} // false
let a = {};
let b = a; // copying by link
b == a // true
As in JavaScript, everything is an object so for falsy and empty, I use the below condition:
if(value && Object.keys(value).length){
// Not falsy and not empty
}
else{
// falsy or empty array/object
}
I was reading a good book on JavaScript.
It started with:
Boolean type take only two literal values: true and false. These are distinct from numeric values, so true is not equal to 1, and false is not equal to 0.
However, I observed following:
if(1==true)
document.write("oh!!! that's true"); //**this is displayed**
I know, that every type in JavaScript has a Boolean equivalent.
But then, what's the truth?
It's true that true and false don't represent any numerical values in Javascript.
In some languages (e.g. C, VB), the boolean values are defined as actual numerical values, so they are just different names for 1 and 0 (or -1 and 0).
In some other languages (e.g. Pascal, C#), there is a distinct boolean type that is not numerical. It's possible to convert between boolean values and numerical values, but it doesn't happen automatically.
Javascript falls in the category that has a distinct boolean type, but on the other hand Javascript is quite keen to convert values between different data types.
For example, eventhough a number is not a boolean, you can use a numeric value where a boolean value is expected. Using if (1) {...} works just as well as if (true) {...}.
When comparing values, like in your example, there is a difference between the == operator and the === operator. The == equality operator happily converts between types to find a match, so 1 == true evaluates to true because true is converted to 1. The === type equality operator doesn't do type conversions, so 1 === true evaluates to false because the values are of different types.
In JavaScript, == is pronounced "Probably Equals".
What I mean by that is that JavaScript will automatically convert the Boolean into an integer and then attempt to compare the two sides.
For real equality, use the === operator.
Try the strict equality comparison:
if(1 === true)
document.write("oh!!! that's true"); //**this is not displayed**
The == operator does conversion from one type to another, the === operator doesn't.
From the ECMAScript specification, Section 11.9.3 The Abstract Equality Comparison Algorithm:
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, in, if (1 == true), true gets coerced to a Number, i.e. Number(true), which results in the value of 1, yielding the final if (1 == 1) which is true.
if (0 == false) is the exact same logic, since Number(false) == 0.
This doesn't happen when you use the strict equals operator === instead:
11.9.6 The Strict Equality Comparison Algorithm
The comparison x === y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
If Type(x) is different from Type(y), return false.
Ah, the dreaded loose comparison operator strikes again. Never use it. Always use strict comparison, === or !== instead.
Bonus fact: 0 == ''
When compare something with Boolean it works like following
Step 1: Convert boolean to Number Number(true) // 1 and Number(false) // 0
Step 2: Compare both sides
boolean == someting
-> Number(boolean) === someting
If compare 1 and 2 with true you will get the following results
true == 1
-> Number(true) === 1
-> 1 === 1
-> true
And
true == 2
-> Number(true) === 1
-> 1 === 2
-> false
Actually every object in javascript resolves to true if it has "a real value" as W3Cschools puts it. That means everything except "", NaN, undefined, null or 0.
Testing a number against a boolean with the == operator indeed is a tad weird, since the boolean gets converted into numerical 1 before comparing, which defies a little bit the logic behind the definition.
This gets even more confusing when you do something like this:
var fred = !!3; // will set fred to true
var joe = !!0; // will set joe to false
alert("fred = "+ fred + ", joe = "+ joe);
not everything in javascript makes a lot of sense ;)
Use === to equate the variables instead of ==.
== checks if the value of the variables is similar
=== checks if the value of the variables and the type of the variables are similar
Notice how
if(0===false) {
document.write("oh!!! that's true");
}
and
if(0==false) {
document.write("oh!!! that's true");
}
give different results
In a way, yes it is 1.
Try these examples in Chrome console:
> 2==true
false
> 1==true
true
> true + 1
2
> true + 2
3
> true + true
2
So, the answer is:
yes, as soon as you use true in any arithmetical context, it's treated as numeric 1, or as Bruce Lee would say, it becomes one. The same way, false is practically zero. But also,
no, if you ask Javascript what it thinks of true, it will say it's a boolean:
> typeof true
'boolean'
It's no surprise in a loosely typed language that sometimes things are not what they are but how you look at them. And if you add true to a string, it will not add 1 but "true" as a string, so at the end of the day, it's by no means equivalent to one. Let me end this with a horrible pun:
true is not a number - but it looks like one
with == you are essentially comparing whether a variable is falsey when comparing to false or truthey when comparing to true. If you use ===, it will compare the exact value of the variables so true will not === 1
Give the following snippet
function countZeroes(array) {
function counter(total, element) {
return total + (element === 0 ? 1 : 0);
}
return reduce(counter, 0, array);
}
What does the === do?
Is reduce a built in function? What does it do?
Please explain the steps of this program.
It is the strict equality operator.
It compares two values and checks to see if they are identical according to the Strict Equality Comparison Algorithm.
This is opposed to ==, which will attempt to coerce one or both of the values being compared if they are of different types. That one uses the Absract Equality Comparison Algorithm.
The rules for the Abstract algorithm can be tricky. You're better off using === unless you have special need for ==.
From the MDC docs
The standard equality operators (== and !=) compare two operands without regard to their type. The strict equality operators (=== and !==) perform equality comparisons on operands of the same type. Use strict equality operators if the operands must be of a specific type as well as value or if the exact type of the operands is important. Otherwise, use the standard equality operators, which allow you to compare the identity of two operands even if they are not of the same type.
With regard to the code, this part:
(element === 0 ? 1 : 0)
...basically says if the value of element is exactly equal to 0, then use 1, otherwise use 0.
So to take that entire line:
return total + (element === 0 ? 1 : 0);
...the return value of the function will be total + 1 if element equals 0, otherwise the return value will be total + 0.
You could rewrite the code using an if-else statement:
if( element === 0 ) {
return total + 1;
} else {
return total + 0;
}
=== is the same as == except it doesn't cast variables
0 == '0' -> true
0 === '0' -> false
reduce isn't a built in function, but what it certainly does is run counter on each element of the array.
so for each element of the array the element is checked to be 0 and if it is the total is incremented.
=== is the identity operator, it's like ==, but does not perform type conversion.
this function appears to count the number of zeros in an array and return the count.
I assume that reduce() acts like Array.prototype.reduce
=== is strictly equal, both sides have to be of the same type and be equal. This is used to avoid the comparison of 2 unequal types (usually boolean false and a number 0)
The "===" is means "exactly equals", as in the value is the same, as is the type. So ...
var x = 5;
if (x === 5) {
alert("This will happen");
} else {
alert ("This won't");
}
It's rarely used.
The reduce function is likely the Array.prototype.reduce() method, which is used to apply a function to values in an array sequentially (sort-of). So, in this usage it is applying the 'counter' function to everything in the array, which will count the # of zeros in the array and return that.
Its a very good question and generally developer coming from other languages always have difficulty understanding the importance of using === as compare to ==
1. 5 == '5' //true why? Because it do
type conversion whereas in case with
=== 5 === '5'//false because '5' is a string as compare to number 5.
2. '\t\r\n' == 0 //true this lack of transitivity is alarming and cause
lot of errors.
3. Use JsLint ...it will help writing better JS code keep your code safe
from this kind of issues.
4. Moreover their is a performance penalty for using == when you are
comparing number with a string.
In my test it turns out that there is
little practical performance
difference between == and ===. While
the strict operator is marginally
faster (roughly 10%) in most browsers
when combined with explicit type
conversion, such as a === +b, the
only real performance gains will come
from avoiding type conversion
entirely. Converting a string to an
integer for comparison with another
integer is significantly slower (up
to 10x) than simple comparing two
integers. You should never allow
integers to be stored as strings
internally, as the type conversion
will incur a performance penalty.
While that was the basic takeaway from the numbers, I did find one interesting outlier when testing with Firefox. In Firefox, the comparison a === +b is about 20x slower than the equivalent a == b when a is an integer and b is a string integer. This result seems suspicious to me, and nothing similar occurred in any other browser. Oddly, when the Firebug script debugger is turned on, this result changes, and a === +b becomes about 10% faster than the other. I'm not sure what to make of this result, but it does serve as a reminder that integers should always be stored in numbers, not in strings.
see other answer about ===.
reduce it built in JS function which uses like "foreach", its moving on every elemnt in the array.
it start with the inital value, which in your case its zero, and then call to counter() and on the first element.
it check it, and return total(which is zero)+ 1 if the element is 0, after the returned value will be the "total" for the 2nd element in the array and so on....
in conclusion: the reduce call to counter on every element of the array,doing the test and adding its value to the (n-1)st element's returned value;
=== is a strict equality comparison. The == operator in JavaScript does type coercion, which often has surprising results, like how ' ' == false. So most JavaScript developers use === where possible.
Hard to tell about reduce(). That is not a built-in global function in JavaScript, but it likely refers to the reduce() method on JavaScript arrays. The reduce() method executes counter() once for every element in the array, and each time it calls counter(), it replaces total with the returned value from the counter() call. So the given function counts the number of elements that are strictly equal to zero in array.