7

The following is done in Firebug:

>>> [1, 2] == [1, 2]
false

>>> ({a : 1}) == ({a : 1})
false

I thought Javscript has some rule that says, if an Object or Array has the same references to the same elements, then they are equal?

But even if I say

>>> foo = {a : 1}
Object { a=1}

>>> [foo] == [foo]
false

>>> ({a: foo}) == ({a: foo})
false

Is there a way to make it so that it can do the element comparison and return true?

nonopolarity
  • 146,324
  • 131
  • 460
  • 740

4 Answers4

6

{ } and [ ] are the same as new Object and new Array

And new Object != new Object (ditto with Array) because they are new and different objects.

If you want to know whether the content of two arbitary objects is the "same" for some value of same then a quick (but slow) fix is

JSON.parse(o) === JSON.parse(o)

A more elegant solution would be to define an equal function (untested)

var equal = function _equal(a, b) {
  // if `===` or `==` pass then short-circuit
  if (a === b || a == b) { 
    return true;
  }
  // get own properties and prototypes
  var protoA = Object.getPrototypeOf(a), 
      protoB = Object.getPrototypeOf(b),
      keysA = Object.keys(a), 
      keysB = Object.keys(b);

  // if protos not same or number of properties not same then false
  if (keysA.length !== keysB.length || protoA !== protoB) {
    return false;
  }
  // recurse equal check on all values for properties of objects
  return keysA.every(function (key) {
    return _equal(a[key], b[key]);
  });
};

equals example

Warning: writing an equality function that "works" on all inputs is hard, some common gotchas are (null == undefined) === true and (NaN === NaN) === false neither of which I gaurd for in my function.

Nor have I dealt with any cross browser problems, I've just assumed ES5 exists.

Raynos
  • 166,823
  • 56
  • 351
  • 396
  • You've got a lot to patch with that function. E.g. `equal({},{}) === false`. Also, I think you mean to recurse with `_equal`. – davin Oct 10 '11 at 14:12
  • @davin `_equal` is just a convention and I dont know how to handle `{}` and `[]` elegantly. That also asks the question of whether `equal(Object.create(foo), Object.create(bar))` should be true or false. – Raynos Oct 10 '11 at 14:13
  • @Raynos, convention, so what? if I decide to change that function to `myEqual` it will break because you need to change that twice. – davin Oct 10 '11 at 14:15
  • @davin of course it will break. If you change it to `myEqual` you need to change all references to `equal` including any references inside `equal` – Raynos Oct 10 '11 at 14:16
  • @Raynos, not if you recurse with the function's name property. That's what I'm trying to tell you. Change the recursion to reference `_equal` and you fix that problem! – davin Oct 10 '11 at 14:17
  • @davin I think I patched the issues you mentioned. – Raynos Oct 10 '11 at 14:19
2

To see what kind of code is necessary to do the deep equality you are talking about, check out Underscore.js's _.isEqual function or QUnit's deepEqual implementation.

Domenic
  • 110,262
  • 41
  • 219
  • 271
0

Its because javascript object literals do not share the same pointers. Instead a new pointer gets created for each one. Consider the following example:

>>> ({a : 1}) == ({a : 1})
false

... but ...

>>> obj = ({a : 1});
Object

>>> obj == obj
true

obj is a pointer to the litteral object { a : 1 }. So this works because the pointers are the same when you compare them

Swift
  • 13,118
  • 5
  • 56
  • 80
0

You are comparing different objects.

>>> var a = [1,2] var b = [1,2]
>>> a == b
false
>>> a == a
true

If you want to test array equality you might want to use some library or just write the test yourself.

andrei3k
  • 31
  • 2