Javascript - deepEqual Comparison
You can use a variable outside the for loop to keep track of the comparison:
var allPropertiesEqual = true;
for (var prop in x) {
if (y.hasOwnProperty(prop)) {
allPropertiesEqual = deepEqual(x[prop], y[prop]) && allPropertiesEqual;
} else {
allPropertiesEqual = false;
}
}
return allPropertiesEqual;
The previous example is not optimized on purpose. Because you're comparing objects, you know that you can return false
as soon as you find an inequality, and you can keep looping while all the previous checked properties are equal:
for (var prop in x) {
if (y.hasOwnProperty(prop)) {
if (! deepEqual(x[prop], y[prop]) )
return false; //first inequality found, return false
} else {
return false; //different properties, so inequality, so return false
}
}
return true;
Feel that this version is a bit more readable (easier to comprehend). The logic is very similar with the top answer though. (ES6 this time)
function deepEqual(obj1, obj2) {
if(obj1 === obj2) // it's just the same object. No need to compare.
return true;
if(isPrimitive(obj1) && isPrimitive(obj2)) // compare primitives
return obj1 === obj2;
if(Object.keys(obj1).length !== Object.keys(obj2).length)
return false;
// compare objects with same number of keys
for(let key in obj1)
{
if(!(key in obj2)) return false; //other object doesn't have this prop
if(!deepEqual(obj1[key], obj2[key])) return false;
}
return true;
}
//check if value is primitive
function isPrimitive(obj)
{
return (obj !== Object(obj));
}
By the way, there is a cheater version of deep equal which works like a charm)) However, it's approximately 1.6 times slower.
As noticed by zero298, this approach is sensitive to the properties ordering and shouldn't be taken seriously
function cheatDeepEqual(obj1, obj2)
{
return JSON.stringify(obj1) === JSON.stringify(obj2);
}
As you suspect, you're returning the match of the first property seen. You should return false
if that property doesn't match, but keep looking otherwise.
Also, return false
if there's no prop
property found on y
(that is, the counts match, but not the actual properties).
If all properties have matched, return true
:
var deepEqual = function (x, y) {
if (x === y) {
return true;
}
else if ((typeof x == "object" && x != null) && (typeof y == "object" && y != null)) {
if (Object.keys(x).length != Object.keys(y).length)
return false;
for (var prop in x) {
if (y.hasOwnProperty(prop))
{
if (! deepEqual(x[prop], y[prop]))
return false;
}
else
return false;
}
return true;
}
else
return false;
}
var deepEqual = function (x, y) {
if (x === y) {
return true;
}
else if ((typeof x == "object" && x != null) && (typeof y == "object" && y != null)) {
if (Object.keys(x).length != Object.keys(y).length)
return false;
for (var prop in x) {
if (y.hasOwnProperty(prop))
{
if (! deepEqual(x[prop], y[prop]))
return false;
}
else
return false;
}
return true;
}
else
return false;
}
var obj = {here: {is: "an", other: "3"}, object: 2};
console.log(deepEqual(obj, obj));
// → true
console.log(deepEqual(obj, {here: 1, object: 2}));
// → false
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));
// → false
console.log(deepEqual(obj, {here: {is: "an", other: "2"}, object: 2}));
// → false
console.log(deepEqual(obj, {here: {is: "an", other: "3"}, object: 2}));
// → true