In Javascript, why does [1,2] == [1,2] resolve to false? [duplicate] - javascript

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

Related

Why is Set.keys() not strictly equal to Set.values(), but set.keys is strictly equal to set.values? [duplicate]

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

Compare 2 elements [duplicate]

This question already has answers here:
Comparing objects in JavaScript
(10 answers)
Closed 12 months ago.
Below is a typical way to check if the focus is on an element certain (txtCmd),
if(document.activeElement === txtCmd){
return
}
I'm worried the operator=== would compare the entire element tree (every attribute and every sub-element) that would be low performance.
Does just compare the elements' Ids is better?
document.activeElement.id === txtCmd.id
PS: There are no different elements with identical ID in the page.
Edit:
I'm from C++. I want something like pointer comparison in C++,
if(&a == &b) {}
=== doesn’t perform any deep comparisons, so it’s not low-performance.
An alternative is the .isSameNode() function:
b.isSameNode(a);
Edit:
I'm from C++. I want something like pointer comparison in C++,
if(&a == &b) {}
That essentially is what == and === do in JavaScript when 2 objects are tested for equality.
JavaScript’s quality operators compare objects by reference if the operands are both objects. a == b and a === b are true only if both a and b reference the same object.
If you compare objects the === operator will perform a reference comparison, so it will only return true only if both operands points to the same object.
It will not cost you more performances but it just does not the same thing than comparing property litteral values.
For a deep comparison "by value" between objects, === doesn't work. You'd have to use a recursive entry by entry comparison, or compare stringified versions of the objects.
Example
const o1 = {"a":1};
const o2 = {"a":1};
const o3 = o1;
console.log(o1 === o2); // false
console.log(o1 === o3); // true
console.log(JSON.stringify(o1) === JSON.stringify(o2)) // true

Comparison Operator in JavaScript [duplicate]

This question already has answers here:
Which equals operator (== vs ===) should be used in JavaScript comparisons?
(48 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
const abc = 5;
const bcd = 5
console.log(abc===bcd)/// return true
This result is surprising to me.
Since abc will be assigned a different memory location ...and bcd has also a different location
why this is returning true
If the code was
const abc = 5
const bcd = abc
console.log(abc === bcd) ///true here make sense
I seem to be be really confused with the first case since abc and bcd are two different variables and have no relation between them
Any related article or blog would really help.
In javascript all primitives (string, nubmer, bigint, boolean, undefined, symbol, null) are immutable and will be compared by value:
All primitives are immutable, i.e., they cannot be altered. It is important not to confuse a primitive itself with a variable assigned a primitive value. The variable may be reassigned a new value, but the existing value can not be changed in the ways that objects, arrays, and functions can be altered.
In comparison to that objects (this also includes arrays and functions, basically everything that is not a primitive) are mutable and will be compared by identity.
Example:
console.log("Primitives compare by value:");
console.log(5 === 5); // true
console.log("foo" === "foo"); // true
console.log(true === true); // true
console.log("Objects compare by identity:");
console.log({} === {}); // false
console.log([] === []); // false
console.log(function(){} === function(){}); // false
Primitive Wrappers
Javascript also has wrapper objects for the primitive types, which might be the source of your question.
These wrappers wrap a primitive value, and are - as the name suggests - objects. So for primitive wrapper instances your code would be correct:
let a = new Number(1);
let b = new Number(1);
console.log("Primitive wrappers are objects:");
console.log(a === a); // true
console.log(a === b); // false
There is a fundamental difference in JavaScript between primitive values (undefined,null, booleans, numbers, and strings) and objects (including arrays and functions)
I. Primitives are compared by value:
Two values are the same only if they have the same value.
If two distinct string values are compared, JavaScript treats them as equal if,
and only if, they have the same length and if the character at each index is the same.
II. Objects are different than primitives.
Objects are not compared by value: Two distinct objects are not equal even if they have the same properties and values.
Therefore, Objects are sometimes called reference types to distinguish them from JavaScript’s primitive types.

Compare JavaScript Array [duplicate]

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

Why isn't [1,2,3] equal to itself in Javascript? [duplicate]

This question already has answers here:
Why doesn't equality check work with arrays [duplicate]
(6 answers)
Closed 2 years ago.
I was playing around with arrays in Javascript today and noticed this little gem:
alert([1, 2, 3] == [1, 2, 3]); //alerts false
It strikes me as rather odd that the array is not equal to itself.
But then I noticed this, which was even weirder:
alert([1, 2, 3] == "1,2,3"); //alerts true
?!?!?!?!!!?
Why in the world is [1, 2, 3] not == to itself but is == to the string?
I realize that == is not the same as ===. Even so, what evilness could cause Mr. Javascript do such weird things?
Ok, so first you need to understand how javascript treats values in your program. All of your variables that you create are going to merely be references to a location in memory where that object is stored. Therefore, when you do this:
alert( [1,2,3] == [1,2,3] );
...it does three things:
Place an array ([1,2,3]) onto the heap
Place another array ([1,2,3]) onto the heap (notice it will have a different memory location)
Compare the two references. They point to different objects in different locations in memory, thus it is considered not equal.
You can check for some sane behavior by running this code:
var a = [1,2,3];
var b = a;
alert (a == b) // Result is true. Both point to the same object.
Now for your question about the string
When you use the == operator tries to convert the two operands to the same type (evil behavior...I know...)
When it does this, it decides to convert both to a string before it does the compare (thus the result is really "1,2,3" === "1,2,3", which evaluates to true.
I can't give you a complete picture, as there are few people who understand every nuance of the madness that is JavaScript, but hopefully this clears some of the fog.
== operator
[..] If either operand is a string, the other operand is converted to a string if possible. [..] If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.
https://developer.mozilla.org/en/JavaScript/Reference/Operators/Comparison_Operators
That is to say, [1, 2, 3] converted to a string equals "1,2,3". One array object does not equal another array object though.
For the first part, you are creating two distinct objects as arrays are just objects and since you created two of them, they are both unique.
Because == only coerces if it has to to get the same type (e.g, only when the types of the operands are different). When doing
alert([1, 2, 3] == [1, 2, 3]); //alerts false
...no coercion is required; both are objects. They're not the same object, so it's false. People think of == as the "coercing" equality operator, and it is, but the key is that it only coerces if it has to.
But doing
alert([1, 2, 3] == "1,2,3"); //alerts true
...involves operands of different types: string and object. So coercion is done. In this case, the object is coerced to string as though with String(obj), which invokes its default toString behavior, which for arrays is .join(). join defaults to "," as the separator, so the resulting string matches "1,2,3". (You can find the full logic of why the object gets coerced to string in the specification.)
The first comparison fails because a basic comparison of two objects will check to see if they are literally the same referenced object, not if the two objects have the same values. If you wish to compare two arrays, you'll have to loop over the values.
function arrayCompare(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (var i = 0, len = arr1.length; i < len; i++) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
Just remember that this is not a recursive comparison, so it will only work on an array of primitive values.
The second comparison works because == will attempt to coerce the types of the arguments, and when you convert an array to a string, that is the result.
[1,2,3].toString() === '1,2,3'
The two Array objects are distinct, and thus not equal when using the == comparison. To compare them, you'd need to loop, checking the index in both are identical (and being recursive if the elements are Arrays too or Objects).
The second is because the Array had its toString() implicitly called which returned '1,2,3' (try it).
This is because by the rules of a == (non strict) comparison in ECMAScript, the left hand operator was coerced to a String (== does type conversion).

Categories

Resources