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.
Related
Seems like the following code should return a true, but it returns false.
var a = {};
var b = {};
console.log(a==b); //returns false
console.log(a===b); //returns false
How does this make sense?
The only difference between regular (==) and strict (===) equality is that the strict equality operator disables type conversion. Since you're already comparing two variables of the same type, the kind of equality operator you use doesn't matter.
Regardless of whether you use regular or strict equality, object comparisons only evaluate to true if you compare the same exact object.
That is, given var a = {}, b = a, c = {};, a == a, a == b, but a != c.
Two different objects (even if they both have zero or the same exact properties) will never compare equally. If you need to compare the equality of two object's properties, this question has very helpful answers.
How does this make sense?
Because "equality" of object references, in terms of the == and === operators, is purely based on whether the references refer to the same object. This is clearly laid out in the abstract equality comparison algorithm (used by ==) and the strict equality comparison algorithm (used by ===).
In your code, when you say a==b or a===b, you're not comparing the objects, you're comparing the references in a and b to see if they refer to the same object. This is just how JavaScript is defined, and in line with how equality operators in many (but not all) other languages are defined (Java, C# [unless the operator is overridden, as it is for string], and C++ for instance).
JavaScript has no inbuilt concept of equivalence, a comparison between objects that indicates whether they're equivalent (e.g., have the same properties with the same values, like Java's Object#equals). You can define one within your own codebase, but there's nothing intrinsic that defines it.
As from The Definitive Guide to Javascript.
Objects are not compared by value: two objects are not equal even if they have the same properties and values. This is true of arrays too: even if they have the same values in the same order.
var o = {x:1}, p = {x:1}; // Two objects with the same properties
o === p // => false: distinct objects are never equal
var a = [], b = []; // Two distinct, empty arrays
a === b // => false: distinct arrays are never equal
Objects are sometimes called reference types to distinguish them from JavaScript’s primitive types. Using this terminology, object values are references, and we say that objects are compared by reference: two object values are the same if and only if they refer to the same underlying object.
var a = {}; // The variable a refers to an empty object.
var b = a; // Now b refers to the same object.
b.property = 1; // Mutate the object referred to by variable b.
a.property // => 1: the change is also visible through variable a.
a === b // => true: a and b refer to the same object, so they are equal.
If we want to compare two distinct objects we must compare their properties.
use JSON.stringify(objname);
var a = {name : "name1"};
var b = {name : "name1"};
var c = JSON.stringify(a);
var d = JSON.stringify(b);
c==d;
//true
Here is a quick explanation of why {} === {} returns false in JavaScript:
From MDN Web Docs - Working with objects: Comparing objects.
In JavaScript, objects are a reference type. Two distinct objects are never equal, even if they have the same properties. Only comparing the same object reference with itself yields true.
// Two variables, two distinct objects with the same properties
var fruit = {name: 'apple'};
var fruitbear = {name: 'apple'};
fruit == fruitbear; // return false
fruit === fruitbear; // return false
// Two variables, a single object
var fruit = {name: 'apple'};
var fruitbear = fruit; // Assign fruit object reference to fruitbear
// Here fruit and fruitbear are pointing to same object
fruit == fruitbear; // return true
fruit === fruitbear; // return true
fruit.name = 'grape';
console.log(fruitbear); // output: { name: "grape" }, instead of { name: "apple" }
For more information about comparison operators, see Comparison operators.
How does this make sense?
Imagine these two objects:
var a = { someVar: 5 }
var b = { another: 'hi' }
Now if you did a === b, you would intuitively think it should be false (which is correct). But do you think it is false because the objects contain different keys, or because they are different objects? Next imagine removing the keys from each object:
delete a.someVar
delete b.another
Both are now empty objects, but the equality check will still be exactly the same, because you are still comparing whether or not a and b are the same object (not whether they contain the same keys and values).
===, the strictly equal operator for objects checks for identity.
Two objects are strictly equal if they refer to the same Object.
Those are two different objects, so they differ.
Think of two empty pages of paper. Their attributes are the same, yet they are not the same thing. If you write something on one of them, the other wouldn't change.
This is a workaround: Object.toJSON(obj1) == Object.toJSON(obj2)
By converting to string, comprasion will basically be in strings
In Javascript each object is unique hence {} == {} or {} === {} returns false. In other words Javascript compares objects by identity, not by value.
Double equal to ( == ) Ex: '1' == 1 returns true because type is excluded
Triple equal to ( === ) Ex: '1' === 1 returns false compares strictly, checks for type even
Seems like the following code should return a true, but it returns false.
var a = {};
var b = {};
console.log(a==b); //returns false
console.log(a===b); //returns false
How does this make sense?
The only difference between regular (==) and strict (===) equality is that the strict equality operator disables type conversion. Since you're already comparing two variables of the same type, the kind of equality operator you use doesn't matter.
Regardless of whether you use regular or strict equality, object comparisons only evaluate to true if you compare the same exact object.
That is, given var a = {}, b = a, c = {};, a == a, a == b, but a != c.
Two different objects (even if they both have zero or the same exact properties) will never compare equally. If you need to compare the equality of two object's properties, this question has very helpful answers.
How does this make sense?
Because "equality" of object references, in terms of the == and === operators, is purely based on whether the references refer to the same object. This is clearly laid out in the abstract equality comparison algorithm (used by ==) and the strict equality comparison algorithm (used by ===).
In your code, when you say a==b or a===b, you're not comparing the objects, you're comparing the references in a and b to see if they refer to the same object. This is just how JavaScript is defined, and in line with how equality operators in many (but not all) other languages are defined (Java, C# [unless the operator is overridden, as it is for string], and C++ for instance).
JavaScript has no inbuilt concept of equivalence, a comparison between objects that indicates whether they're equivalent (e.g., have the same properties with the same values, like Java's Object#equals). You can define one within your own codebase, but there's nothing intrinsic that defines it.
As from The Definitive Guide to Javascript.
Objects are not compared by value: two objects are not equal even if they have the same properties and values. This is true of arrays too: even if they have the same values in the same order.
var o = {x:1}, p = {x:1}; // Two objects with the same properties
o === p // => false: distinct objects are never equal
var a = [], b = []; // Two distinct, empty arrays
a === b // => false: distinct arrays are never equal
Objects are sometimes called reference types to distinguish them from JavaScript’s primitive types. Using this terminology, object values are references, and we say that objects are compared by reference: two object values are the same if and only if they refer to the same underlying object.
var a = {}; // The variable a refers to an empty object.
var b = a; // Now b refers to the same object.
b.property = 1; // Mutate the object referred to by variable b.
a.property // => 1: the change is also visible through variable a.
a === b // => true: a and b refer to the same object, so they are equal.
If we want to compare two distinct objects we must compare their properties.
use JSON.stringify(objname);
var a = {name : "name1"};
var b = {name : "name1"};
var c = JSON.stringify(a);
var d = JSON.stringify(b);
c==d;
//true
Here is a quick explanation of why {} === {} returns false in JavaScript:
From MDN Web Docs - Working with objects: Comparing objects.
In JavaScript, objects are a reference type. Two distinct objects are never equal, even if they have the same properties. Only comparing the same object reference with itself yields true.
// Two variables, two distinct objects with the same properties
var fruit = {name: 'apple'};
var fruitbear = {name: 'apple'};
fruit == fruitbear; // return false
fruit === fruitbear; // return false
// Two variables, a single object
var fruit = {name: 'apple'};
var fruitbear = fruit; // Assign fruit object reference to fruitbear
// Here fruit and fruitbear are pointing to same object
fruit == fruitbear; // return true
fruit === fruitbear; // return true
fruit.name = 'grape';
console.log(fruitbear); // output: { name: "grape" }, instead of { name: "apple" }
For more information about comparison operators, see Comparison operators.
How does this make sense?
Imagine these two objects:
var a = { someVar: 5 }
var b = { another: 'hi' }
Now if you did a === b, you would intuitively think it should be false (which is correct). But do you think it is false because the objects contain different keys, or because they are different objects? Next imagine removing the keys from each object:
delete a.someVar
delete b.another
Both are now empty objects, but the equality check will still be exactly the same, because you are still comparing whether or not a and b are the same object (not whether they contain the same keys and values).
===, the strictly equal operator for objects checks for identity.
Two objects are strictly equal if they refer to the same Object.
Those are two different objects, so they differ.
Think of two empty pages of paper. Their attributes are the same, yet they are not the same thing. If you write something on one of them, the other wouldn't change.
This is a workaround: Object.toJSON(obj1) == Object.toJSON(obj2)
By converting to string, comprasion will basically be in strings
In Javascript each object is unique hence {} == {} or {} === {} returns false. In other words Javascript compares objects by identity, not by value.
Double equal to ( == ) Ex: '1' == 1 returns true because type is excluded
Triple equal to ( === ) Ex: '1' === 1 returns false compares strictly, checks for type even
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:
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