This question already has answers here:
How to compare arrays in JavaScript?
(55 answers)
Closed 9 years ago.
I was asked to write a function sortByFoo in Javascript that would react correctly to this test :
// Does not crash on an empty array
console.log(sortByFoo([]) === []);
But I've tried something :
[] === [];
>> false
Just so I can be sure, such a test would always fail, no matter the sortByFoo function, wouldn't it ?
But I'd like to have an explanation on why this happens. Why [] isn't identical/equal to [] ?
Please forgive my approximate english, it is not my native language :p
If you look at the specification for javascript/ecmascript, particularly section 11.9.6, you will see how comparisons with === are performed.
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.
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return false.
Since your arrays go all the way down to the seventh step they will have to be the same object, not just two identical objects. The same goes for the regular equality operator (==).
Because every time you write [] you are calling array's constructor.
[] is the same as new Array(), and in Javascript new objects compared with equals method are different. See the reference, it is the same as new Object() when using {}.
When you do [] === [] you're comparing references and not values (or deep comparison by values).
Take a look at this solution for javascript array comparison: Comparing two arrays in Javascript
Yes, you are correct that two array literals are never equal. That's because they are references to two separate instances of arrays.
The code to describe the test should be written:
var arr = [];
var result = sortByFoo(arr);
console.log(result === arr && result.length == 0);
Checking that the reference returned by the function is the same that was sent in, and that the array is still empty, ensures that the function returned the same array unchanged.
Related
With the === operator in Javascript, if it operators on primitives, it returns false if either the values are different or the types are different. If it's operating on non-primitives, it returns false if the two operands don't point to the same object.
This seems like the === has separate definitions when applied to primitives and non-primitives. Like "if operands are primitives, do this, else do this". Is there a broader definition of === that encompasses its treatment of both primitives and non-primitives? Like "whether primitives or non-primitive, do this"?
Yes, to some extent - there's a bit of a process here.
7.2.15 IsStrictlyEqual ( x, y )
If Type(x) is different from Type(y), return false.
If x is a Number, then Return Number::equal(x, y).
Return SameValueNonNumber(x, y).
and
7.2.12 SameValueNonNumber ( x, y )
Assert: Type(x) is the same as Type(y).
If x is a BigInt, then
a. Return BigInt::equal(x, y).
If x is undefined, return true.
If x is null, return true.
If x is a String, then
a. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false.
If x is a Boolean, then
a. If x and y are both true or both false, return true; otherwise, return false.
If x is a Symbol, then
a. If x and y are both the same Symbol value, return true; otherwise, return false.
If x and y are the same Object value, return true. Otherwise, return false.
The only real answer here is the spec, where we see === defined:
EqualityExpression : EqualityExpression === RelationalExpression
1. Let lref be ? Evaluation of EqualityExpression.
2. Let lval be ? GetValue(lref).
3. Let rref be ? Evaluation of RelationalExpression.
4. Let rval be ? GetValue(rref).
5. Return IsStrictlyEqual(rval, lval).
So we're comparing "whatever the GetValue spec function says we should be comparing", paired with "and we have to use the strict equality test for that", so we're not so much comparing "two primitive values, or two references". There's a few more steps involved, which have zero relevance to "actually using JS" in most circumstances, so for practical purposes they simply don't matter...but when you have fundamental questions, the spec is the fundaments =)
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).
The Python use of 'is' seems to be similar to JavaScript '===' but not quite.
Here they talk about exact instances:
http://www.learnpython.org/en/Conditions
here (for JS) they talk about "equal AND the same type."
http://www.w3schools.com/js/js_comparisons.asp
SO can you have two different instances of (say) a string of "Bob" and have them not return true when compared using 'is'? Or is it infact the same as ===?
I am guessing this is related to strict vs non-strict typed languages. . . .
Python Part
SO can you have two different instances of (say) a string of "Bob" and
have them not return true when compared using 'is'? Or is it infact
the same as ===?
a = "Bob"
b = "{}".format("Bob")
print a, b
print a is b, a == b
Output
Bob Bob
False True
Note: In most of the Python implementations, compile time Strings are interned.
Another example,
print 3 is 2+1
print 300 is 200+100
Output
True
False
This is because, small ints (-5 to 256) in Python are cached internally. So, whenever they are used in the programs, the cached integers are used. So, is will return True for them. But if we choose bigger numbers, like in the second example, (300 is 200+100) it is not True, because they are NOT cached.
Conclusion:
is will return True only when the objects being compared are the same object, which means they point to the same location in memory. (It solely depends on the python implementation to cache/intern objects. In that case, is will return True)
Rule of thumb:
NEVER use is operator to check if two objects have the same value.
JavaScript Part
Other part of your question is about === operator. Lets see how that operator works.
Quoting from ECMA 5.1 Specs, The Strict Equality Comparison Algorithm is defined like this
If Type(x) is different from Type(y), return false.
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is Number, then
If x is NaN, return false.
If y is NaN, return false.
If x is the same Number value as y, return true.
If x is +0 and y is −0, return true.
If x is −0 and y is +0, return true.
Return false.
If Type(x) is String, then return true if x and y are exactly the
same sequence of characters (same length and same characters in
corresponding positions); otherwise, return false.
If Type(x) is Boolean, return true if x and y are both true or both
false; otherwise, return false.
Return true if x and y refer to the same object. Otherwise, return
false.
Final Conclusion
We can NOT compare Python's is operator and JavaScript's === operator, because Python's is operator does only the last item in the Strict Equality Comparison Algorithm.
7. Return true if x and y refer to the same object. Otherwise, return false.
Completely different.
>>> a = 'foo'
>>> b = 'bar'
>>> a + b is 'foobar'
False
>>> 1000 + 1 is 1001
False
>>> a = "Hello, World!!!"
>>> b = "Hello, World!!!"
>>> a is b
False
However note that:
>>> a = "Bob"
>>> b = "Bob"
>>> a is b
True
In this case it condition was True because the compiler is free to intern string literals, and thus reuse the same object, and it does do that with small strings. However there is no guarantee as to when this happens of if this happens at all and the behaviour changes between versions and implementations.
A realiable False output should be:
>>> a = 'Hello, World!!!!'[:-1]
>>> b = 'Hello, World!!!!'[:-1]
>>> a is b
False
Or anything that actually computes the strings.
Python's is keyword compares references (and so is about identity) while === does a minimal amount of coercion (and is therefore concerned with equality, at least in the case of primitives) so they are different.
As I understand it, things that are concerned with identity are concerned with uniqueness from the runtime's point of view (do these two variables point to the same address in memory) while equality is concerned with the uniqueness of the contents of the variables (are these two variables equivalent, regardless of where they are placed in memory relative to each other).
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
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why [] == [] is false in javascript?
I would like to ask about strange thing, i.e.:
var x = "pl";
var y = ["pl"];
[x] == y; // false - why?
x == y; // true - how ?
x === y; // false - okay
Can some one explain it?
Thanks in advance.
The first one is false because you're comparing two arrays (which are objects) - a comparison which will always be false unless the objects are actually the same object, or if the objects are coerced to a different type of value like in the second comparison.
In the second comparison, y is coerced to be a string value, and then found to be equal to "pl".
For instance, this code:
["pl"] + "foo" → "plfoo"
Incidentally, this is why you should always use === instead of == - it doesn't result in any surprising coercions. That's why the third comparison is false.
Array to Array (abstract equality comparison)
[x] == y; // false - why?
[x] and y do not refer to the same object. Arrays are objects and the == operator tests that they are the same object, not simply two objects having identical values for all properties. In order to determine object-equality in that way, you'll have to manually enumerate the properties of each object and test each value.
According to The Abstract Equality Comparison Algorithm used by ==:
Return true if x and y refer to the same object. Otherwise, return false.
String to Array (abstract equality comparison)
x == y; // true - how ? oO
y, an array, is coerced into a string because you used == when comparing it to x, a string.
According to The Abstract Equality Comparison Algorithm used by ==:
If Type(x) is either String or Number and Type(y) is Object, return
the result of the comparison x == ToPrimitive(y).
String to Array (strict equality comparison)
x === y; // fasle - okey
===, unlike ==, will not coerce y into a string... so, you're comparing a string to an object.
According to The Strict Equality Comparison Algorithm used by ===:
If Type(x) is different from Type(y), return false.
[x] == y;
['pl'] == ['p1'] - comparing refs on 2 different arrays in memory
x == y;
The same as "pl" == ["p1"].toString(). JS convert the second argument to the string because the first one is also string