Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object comparison in JavaScript [duplicate]

What is the best way to compare objects in JavaScript?

Example:

var user1 = {name : "nerd", org: "dev"}; var user2 = {name : "nerd", org: "dev"}; var eq = user1 == user2; alert(eq); // gives false 

I know that two objects are equal if they refer to the exact same object, but is there a way to check if they have the same attributes' values?

The following way works for me, but is it the only possibility?

var eq = Object.toJSON(user1) == Object.toJSON(user2); alert(eq); // gives true 
like image 485
spankmaster79 Avatar asked Jul 01 '09 12:07

spankmaster79


People also ask

Can you compare two objects in JavaScript?

Objects are not like arrays or strings. So simply comparing by using "===" or "==" is not possible. Here to compare we have to first stringify the object and then using equality operators it is possible to compare the objects.

What is the best way to compare objects in JavaScript?

Comparing objects is easy, use === or Object.is(). This function returns true if they have the same reference and false if they do not. Again, let me stress, it is comparing the references to the objects, not the keys and values of the objects. So, from Example 3, Object.is(obj1,obj2); would return false.

Can object in JavaScript have duplicate keys?

No, JavaScript objects cannot have duplicate keys. The keys must all be unique.


1 Answers

Unfortunately there is no perfect way, unless you use _proto_ recursively and access all non-enumerable properties, but this works in Firefox only.

So the best I can do is to guess usage scenarios.


1) Fast and limited.

Works when you have simple JSON-style objects without methods and DOM nodes inside:

 JSON.stringify(obj1) === JSON.stringify(obj2)  

The ORDER of the properties IS IMPORTANT, so this method will return false for following objects:

 x = {a: 1, b: 2};  y = {b: 2, a: 1}; 

2) Slow and more generic.

Compares objects without digging into prototypes, then compares properties' projections recursively, and also compares constructors.

This is almost correct algorithm:

function deepCompare () {   var i, l, leftChain, rightChain;    function compare2Objects (x, y) {     var p;      // remember that NaN === NaN returns false     // and isNaN(undefined) returns true     if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {          return true;     }      // Compare primitives and functions.          // Check if both arguments link to the same object.     // Especially useful on the step where we compare prototypes     if (x === y) {         return true;     }      // Works in case when functions are created in constructor.     // Comparing dates is a common scenario. Another built-ins?     // We can even handle functions passed across iframes     if ((typeof x === 'function' && typeof y === 'function') ||        (x instanceof Date && y instanceof Date) ||        (x instanceof RegExp && y instanceof RegExp) ||        (x instanceof String && y instanceof String) ||        (x instanceof Number && y instanceof Number)) {         return x.toString() === y.toString();     }      // At last checking prototypes as good as we can     if (!(x instanceof Object && y instanceof Object)) {         return false;     }      if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {         return false;     }      if (x.constructor !== y.constructor) {         return false;     }      if (x.prototype !== y.prototype) {         return false;     }      // Check for infinitive linking loops     if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {          return false;     }      // Quick checking of one object being a subset of another.     // todo: cache the structure of arguments[0] for performance     for (p in y) {         if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {             return false;         }         else if (typeof y[p] !== typeof x[p]) {             return false;         }     }      for (p in x) {         if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {             return false;         }         else if (typeof y[p] !== typeof x[p]) {             return false;         }          switch (typeof (x[p])) {             case 'object':             case 'function':                  leftChain.push(x);                 rightChain.push(y);                  if (!compare2Objects (x[p], y[p])) {                     return false;                 }                  leftChain.pop();                 rightChain.pop();                 break;              default:                 if (x[p] !== y[p]) {                     return false;                 }                 break;         }     }      return true;   }    if (arguments.length < 1) {     return true; //Die silently? Don't know how to handle such case, please help...     // throw "Need two or more arguments to compare";   }    for (i = 1, l = arguments.length; i < l; i++) {        leftChain = []; //Todo: this can be cached       rightChain = [];        if (!compare2Objects(arguments[0], arguments[i])) {           return false;       }   }    return true; } 

Known issues (well, they have very low priority, probably you'll never notice them):

  • objects with different prototype structure but same projection
  • functions may have identical text but refer to different closures

Tests: passes tests are from How to determine equality for two JavaScript objects?.

like image 195
crazyx Avatar answered Oct 14 '22 20:10

crazyx