Why or how does this prove JavaScript array equality? - javascript

In this answer there is a simple function that will return array equality for arrays that contain primitive values.
However, I'm not sure why it works. Here is the function:
function arrays_equal(a,b) { return !!a && !!b && !(a<b || b<a); }
I'm mostly interested in the second half; this bit:
!(a<b || b<a)
Why does the < and > work when comparing the arrays but the == doesn't?
How do the less than and greater than methods work within JavaScript?

With </>, the arrays are converted to strings first, and as such do not provide a reliable method of checking equality.
== does not work because objects are checked by reference:
[] == []; // false, two separate objects
var a = [];
a == a; // true, refer to the same object
The </> trick is flawed:
var a = [1, [2, 3]],
b = [[1, 2], 3];
!(a<b || b<a); // true
This evaluates to true, because they are both converted to the string "1,2,3" before they are checked (</> do not "directly" work for objects).
So basically, you are comparing equality of the strings. For strings, a == b is indeed the same as !(a<b || b<a) - </> for strings check character codes, so two equal strings are neither "smaller" nor "greater" because that's not the case for any character code in the strings.

However, I'm not sure why it works.
It doesn't work. Consider
arrays_equal(["1,2"], [1,2])
produces true even though by any definition of array equality based on element-wise comparison, they are different.
arrays_equal([[]], [])
and
arrays_equal([""], [])
are also spurious positives.
Simply adding length checking won't help as demonstrated by
arrays_equal(["1,2",3], [1,"2,3"])
arrays_equal(
["",","],
[",",""])
EDIT:
If you want a succinct way to test structural similarity, I suggest:
function structurallyEquivalent(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
It doesn't stop early on inputs that are obviously different -- it walks both object graphs regardless of how disimilar they are, but so does the function in the OP.
One caveat: when you're using non-native JSON.stringify, it may do strange things for cyclic inputs like:
var input = [];
input[0] = input;

You can compare any two objects using ==. But since > and < are not defined for objects, they are converted to strings. Therefore, [1,2,3]>[2,1,3] is actually doing "1,2,3">"2,1,3"

Related

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

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

Object and primitive type equality

I know that identical objects are not equal, i.e:
var obj = { name: "Value" };
var obj2 = { name: "Value" };
console.log("obj equals obj2: " + (obj === obj2)); //evaluates to false
Yet primitive types are:
var str = "string1";
var str2 = "string1";
console.log("str equals str2: " + (str === str2)); //evaluates to true
My question is why. Why are objects and primitives treated differently? If an object is nothing but an empty container, with only the attributes you specify to put in the container, why wouldn't the container's identical attributes evaluate to be the same? I looked around for this answer on SO and elsewhere, but didn't find an answer.
Is a JS object treated as something different in the DOM than a primitive type?
Thanks
This seems to really be a question about === so let's look at the Strict Equality Comparison Algorithm, in which point 7 says
Return true if x and y refer to the same object. Otherwise, return false.
So what does it mean to be "the same object"? It means they don't just look like eachother, but are at the same place in memory too. This means that the only time when an Object is === to an Object is when they're the same thing.
var a = {},
b = {}, // identical to `a`
c = a; // same as `a`
a === b; // false
a === c; // true
b === c; // false
When a variable's value is an object, well, it isn't an object: it's a reference to an object. Two variables that contain references to the same object are indeed equal:
var myObj = { hello: "world" };
var a = myObj;
var b = myObj;
if (a == b) alert("YES!!"); // YES!!
When the == operator has object references on both sides, the comparison made is to test whether the objects refer to the same object. When primitive values are involved, the semantics are different: the values are directly compared.
Generally, === operator checks for types, and if they are the same, checks values. Object type contains a reference, so, to be equal, they have to reference the same object and be of the same type. String literal value is not a reference, it is a value, so the === will produce true for string literals, but not for "abc" === new String("abc") because latter is an Object.
More information can be found here: A lot of details can be explored from here: Which equals operator (== vs ===) should be used in JavaScript comparisons?
First off, JavaScript objects aren't part of the DOM. The DOM (Document Object Model) are the HTML elements which make up your page. They cooperate together, but aren't directly linked.
Basically, yes, primitives are a special case. You can kind of think of it as if the value of a primitive is a constant (in a sense).
For example, take the example of the number 5. No matter how many times I declare 5, 5 will always equal 5. Thus, it isn't a stretch to say that {var a holding the value 5} is equivalent to {var b holding the value 5}. This concept is a little fuzzier with strings, but it still holds. A string that is "abc" is always the same as any other variable holding a string that is "abc".
This doesn't apply to objects either.
If you have two variables hold the same object, they are eqivalent.
var a = {};
var b = a;
console.log(a == b); // true
console.log(a === b); // true
However, if we create two objects that look similar:
var a = {};
var b = {};
console.log(a == b); // false
console.log(a === b); // false
This seems a bit weird at first, but think about the inner workings that are going on. Consider that when you pass an object in to a function, if you change that object, it is changed outside of the function to. It's passed by reference.
This means you can think of a pointer (a memory address) being stored in the variables. So, if you imagine that they have memory address in them (like 0x123456 and 0x654321), then it makes a little more sense (0x123456 and 0x654321 are different, so you wouldn't expend them to be equal). They are two separate things taking up their own area in the memory.
Make sense?
You can answer to this question at several levels.
strings
Factually, yes, strings are handled differently from objects as far as strict comparison operator is concerned.
Semantically, that is more convenient than having to resort to strcmp or equivalent mechanisms to compare two strings.
Implementation-wise, the cost is neglectible, so JavaScript can offer you that convenience.
By the way, people telling the strict equality operator checks if both variables point to the same memory location are wrong. In case of strings, === will succeed if the string contents are equal, wherever they might be located in memory.
Objects
Semantically, contrary to primitive types like numbers or strings, it is difficult to offer a consistent set of comparison operators for objects.
You could do an in-depth comparison for equality, but greater/lower operators would make little sense.
The choice of Javascript is rather inconsistent here.
the semantics of equality comparison (be it == or ===) are limited to references
(i.e. == or === will succeed if the references are equal).
Implementation-wise, a deep comparison could be quite costly.
There are also subtelties as how to interpret undefined properties.
At any rate, JavaScript did not choose to implement a deep comparison, so if you want one, you'll have to do it yourself.
And there have been terabytes of code written to try and provide the ideal in-depth object comparison function.
ordered comparison is handled quite differently.
You can define a valueOf method that will return whatever primitive value you want to be used for ordered comparison, e.g
myObject.prototype.valueOf = function(){return this.my_comparison_value; };
If not explicitely defined, valueOf will default to "[object Object]".
So if you don't supply a valueOf method:
< and > operators will always return false (which kind of makes sense).
>= and <= will always return true, regardless of the references being equal or not
(which makes a lot less sense).
Now if you take the pain to define a valueOf, equality comparison will still not use it.
The only way to have a consistent behaviour would be to combine <= and >=, e.g.
if (a >= b && a <= b) { // equality using valueOf
For browser-supplied primitive objects like DOM elements, the behaviour of ordering operators depends on what the browser decided to return as a default value.
I would not recomend using that unless you really know what you're doing.

How to compare two regexps?

Why do
console.log(/a/ == /a/);
and
var regexp1 = /a/;
var regexp2 = /a/;
console.log(regexp1 == regexp2);
both return false?
Try this:
String(regexp1) === String(regexp2))
You are getting false because those two are different objects.
"Problem":
regex is an object- a reference type, so the comparsion is done by reference, and those are two different objects.
console.log(typeof /a/); // "object"
If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.
MDN
Solution:
​var a = /a/;
var b = /a/;
console.log(​​​a.toString() === b.toString()); // true! yessss!
Live DEMO
Another "hack" to force the toString() on the regexes is:
console.log(a + "" === b + "");​
Just a guess - but doesn't JavaScript create a RegExp object for your regex, and therefore because you have created two different objects (even though they have the same "value") they're actually different?
For primitive data types like int, string, boolean javascript knows what to compare, but for objects like date or regex that operator only looks at the place in memory, because you define your regexes independently they have two different places in memory so they are not equal.

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).

Javascript === (triple equals)

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.

Categories

Resources