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
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.
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.
No, JavaScript objects cannot have duplicate keys. The keys must all be unique.
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.
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};
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):
Tests: passes tests are from How to determine equality for two JavaScript objects?.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With