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
Related
I know the difference between == and === when applied to primitive values. But for objects, they both seem to be a simple identity comparison.
var a = {}
var b = a
var c = {}
a == b // true
a === b // true
a == c // false
a === c // false
Is there any situation where comparing two objects will provide different results for each operator, or are they functionally equivalent?
Yes, comparing two objects with == is the same as comparing them with ===. Just as comparing two strings with == is the same as ===. If the type of values are the same, both comparing methods will give the same result. As the specification states:
7.2.14 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(x) is the same as Type(y), then
Return the result of
performing Strict Equality Comparison x === y.
Looks like it
The only way I know to "check for object equality" in javascript is to deep check every possible key (but even then it is just duck type checking)
The extra = in === ensures both sides are of the same type. a and c both are objects, the same type. So == or === is irrelevant here.
Well... === is "compare identity and type". You've determined that you're comparing two objects (so "type" is the same), that leaves "compare identity", which is the same as ==.
Likewise, if you compare two numbers, since you already know they are the same type (number), === is the same as ==. There is nothing special or different about objects vs. primitives here. It's just that the only type for objects is object.
This question already has answers here:
Why doesn't equality check work with arrays [duplicate]
(6 answers)
Closed 7 years ago.
I am storing (x,y) coordinates as 2-element arrays.
var coordinateA = [0,3];
var coordinateB = [1,2];
I also have a longer array containing many of these coordinates:
var coordinates = [coordinateA, coordinateB]
Imagine my surprise when the following statements turned out to be false:
jQuery.inArray(coordinateA, coordinates); // returns -1
coordinateA == coordinates[0]; // returns false
[0,3] == [0,3]; // returns false(!)
coordinateA == coordinateA; // returns true, thankfully
Could someone help me understand why this is the case? Also, is there a better way to represent 2D coordinates in Javascript? Thanks for any clues or suggestions.
This is because you have two separate array references.
The equality operator is checking that the references are equal, not the content of the arrays.
One of the puzzling things about JavaScript is how equality is dealt with. I will do my best to explain this.
The equality rules can be quite hard to grasp. Generally speaking, you can compare by relative equality (==) or strict equality (===).
relative equality:
This compares by value only and does not care about type.
Example
var x = '2';
var y = 2;
x == y;
=> false;
In relative equality, the string "2" equals the number 2. This will return true since types are not compared
strict equality
This compares by both value and type.
Example
var x = '2';
var y = 2;
x === y;
=> false
In this case, the string "2" does NOT equal the number 2. Because String and Number are two different types.
Comparisons with arrays and objects are done differently though.
In your case, arrays are considered objects.
typeof([1,2])
=> "object"
In JavaScript, all objects are different. They are compared by their object ids. To determine if arrays are equal, you have to perform type conversion to a string.
String([1,2]) == String([1,2])
=> true
However, the underscore library has an is_equal method that can determine whether two arrays are equal
_.isEqual(array1, array2);
Underscore does this by performing a deep comparison between two objects to determine if they should be considered equal.
It's important to note that order matters here, as it does in the string comparison.
_isEqual([1,2], [1,2])
=> true
_isEqual([1,2], [2,1])
=> false
We suppose that we have 3 variables : a,b and c
var a = new Boolean(true);
var b = true;
var c = new Boolean(true);
console.log("First comparison : ", a == b);
// true
console.log("Second comparison : ", b == c);
// true
console.log("Contradiction : ", a == c);
// false
I already know that the keyword 'new' creates a new object.
The type of this object, is simply object.
Mathematically, how can we explain this contradiction ?
In the first two examples, since the comparison involves a primitive value of b, a and c end up being coerced to primitives. In the last case, on the other hand, you are comparing two distinct objects, and therefore no coercion takes place.
To be precise, the double-equal comparison with a boolean uses this rule from the spec (taking the case of b == c):
If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
So this means that ToNumber(b) is compared with c. ToNumber(b) is 1. So we are comparing 1 with c. Next, the following rule is applied:
If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
So this means we compare 1 with ToPrimitive(c) which is ToPrimitive(Boolean(true)). ToPrimitive invokes valueOf, which yields 1. So we compare 1 to 1. QED.
In the case of your third example, the following portion of the spec applies:
If Type(x) is the same as Type(y), then...Return true if x and y refer to the same object. Otherwise, return false.
To answer your question:
Mathematically, how can we explain this contradiction ?
It's not a matter of mathematics. It's a matter of the definition of comparisons in the JS spec.
Mathematically, how can we explain this contradiction?
If you think this is a contradiction is probably because you assumed that == defines an equivalence relation.
But it doesn't:
It doesn't satisfy reflexivity, e.g. NaN != NaN.
It doesn't satisfy transitivity, as you noticed.
It satisfies symmetry, though, but that alone is not enough.
I don't think this kind of behaviour can be explained from a mathematical standpoint.
What you are doing on the variables a and c is commonly referred as "boxing": taking a Javascript primitive value (undefined, null, String, Number, Boolean, Symbol in ES6) and calling it with the newoperator.
The result of:
var a = new Boolean(true);
is a Javascript Objectwrapping a Boolean primitive value.
The same invocation pattern implicitly happens when you use a primitive value as the context (this) in some of the language built-in facilities such as Function.prototype.call and Function.prototype.apply
Even replacing ==with === would yield the same results, and that's because of how the Objects comparison work in JS.
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).
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.