Question (From Eloquent Javascript 2nd Edition, Chapter 4, Exercise 4):
Write a function, deepEqual, that takes two values and returns true only if they are the same value or are objects with the same properties whose values are also equal when compared with a recursive call to deepEqual.
Test Cases:
var obj = {here: {is: "an"}, 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})); // → true
My code:
var deepEqual = function (x, y) { 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)) return deepEqual(x[prop], y[prop]); /*This is most likely where my error is. The question states that all the values should be checked via recursion; however, with the current setup, only the first set of properties will be checked. It passes the test cases, but I would like to solve the problem correctly!*/ } } else if (x !== y) return false; else return true; }
I think I have the general idea down; however, like I stated in the comment, the program will not check the second property in the objects. I feel like I have a structural/logic problem and am simply using recursion in the wrong way, as I originally intended to loop through the properties, use recursion to compare the values of the first property, then continue on in the loop to the next property and compare again. Although, I’m not sure if that’s even possible?
I’ve given a good amount of thought and tried a couple different approaches, but this was the most correct answer I’ve come to so far. Any possible tips to point me in the right direction?
Advertisement
Answer
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