Javascript - deepEqual比较

Gav*_*cek 11 javascript recursion

问题(来自Eloquent Javascript第2版,第4章,练习4):

编写一个函数deepEqual,它接受两个值,只有当它们是相同的值时返回true,或者是与对deepEqual的递归调用相比,其值也相等的对象.

测试用例:

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
Run Code Online (Sandbox Code Playgroud)

我的代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

我想我有一般的想法; 但是,就像我在评论中所说的那样,程序不会检查对象中的第二个属性.我觉得我有结构/逻辑问题而且只是以错误的方式使用递归,因为我原本打算循环遍历属性,使用递归来比较第一个属性的值,然后继续循环到下一个属性财产并再次比较.虽然,我不确定这是否可能?

我已经给出了很多想法,尝试了几种不同的方法,但这是我到目前为止最正确的答案.任何可能的提示,指出我正确的方向?

Pau*_*oub 24

正如您所怀疑的那样,您将返回所看到的第一个房产的匹配.false如果该属性不匹配,您应该返回,但请继续查看.

此外,false如果找不到任何prop属性,则返回y(即,计数匹配,但不是实际属性).

如果所有属性都匹配,则返回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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Dan*_*nov 6

觉得这个版本更具可读性(更容易理解)。逻辑与最佳答案非常相似。(这次是ES6)

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));
}
Run Code Online (Sandbox Code Playgroud)

顺便说一下,有一个深层骗子的作弊者版本,它就像一个符咒一样)。但是,它慢了大约1.6倍。

正如zero298所注意到的那样,这种方法对属性排序很敏感,因此不应认真对待

function cheatDeepEqual(obj1, obj2)
{
    return JSON.stringify(obj1) === JSON.stringify(obj2);
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为如果属性顺序不同,“骗子”版本可能会失败。考虑在node.js中测试的这个示例:JSON.stringify({foo:“ bar”,fizz:“ buzz”})=== JSON.stringify({fizz:“ buzz”,foo:“ bar”}); `是错误的;但是`JSON.stringify({foo:“ bar”,fizz:“ buzz”}))=== JSON.stringify({foo:“ bar”,fizz:“ buzz”});`是真实的。 (2认同)