比较两个对象,看是否相等

时间:2016-06-20 19:25:46

标签: javascript

目前我正在关注一本书并且非常困惑,并且多次尝试了解以下代码。我的第一个困惑实际上是在解决比较两个对象 a b 的问题。

 function deepEqual(a, b) {
  if (a === b) return true;

  if (a == null || typeof a != "object" ||
      b == null || typeof b != "object")
    return false;

  var propsInA = 0, propsInB = 0;

  for (var prop in a)
    propsInA += 1;

  for (var prop in b) {
    propsInB += 1;
    if (!(prop in a) || !deepEqual(a[prop], b[prop]))
      return false;
  }

  return propsInA == propsInB;
}

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

4 个答案:

答案 0 :(得分:3)

function deepEqual(a, b) {
  if (a === b) return true;

首先,我们正在检查ab是否严格相等(意思是,“指的是完全相同的东西”) 。大多数事情,如字符串和数字,如果相等,都会通过这个测试;对象是例外,因为两个“相同”的对象可能不一定是相同的对象(它们看起来可能相同)。

  if (a == null || typeof a != "object" ||
      b == null || typeof b != "object")
    return false;

然后我们说如果两者中的任何一个不是对象,并且它们没有通过最后一次测试,那么它们就不能相同。同样,对象在这里是例外,因此剩下的代码将处理ab都是对象的情况。

  var propsInA = 0, propsInB = 0;

  for (var prop in a)
    propsInA += 1;

此代码只计算a的属性数。

  for (var prop in b) {
    propsInB += 1;
    if (!(prop in a) || !deepEqual(a[prop], b[prop]))
      return false;
  }

此代码获取b中的每个属性,并检查a是否包含具有相同值的相同属性。如果a没有b具有的属性,或者它们不同,则两个对象不能相等。

  return propsInA == propsInB;
}

最后,如果ab没有相同数量的属性,那么它们就不能相等。但是,如果它们具有相同数量的属性,则ab必须相同,因为a具有b具有的所有属性,和只有那些

答案 1 :(得分:1)

我将引导您完成它。

if (a === b) return true;

我们检查这些是否相同,我们稍后会再回到这里。

if (a == null || typeof a != "object" ||
      b == null || typeof b != "object")
    return false;

我们检查是否定义了这些东西中的一个或两个。我们也会回到这里。

记住前两个片段,在我们递归调用函数之前,它们不会发挥作用。

var propsInA = 0, propsInB = 0;

这些将用于跟踪对象A和B中的属性数量

for (var prop in a)
    propsInA += 1;

  for (var prop in b) {
    propsInB += 1;
    if (!(prop in a) || !deepEqual(a[prop], b[prop]))
      return false;
  }

  return propsInA == propsInB;
}

我们有两个for循环。第一个只是循环遍历A中的所有属性(如果你不熟悉的话,在语法中查找...),并且每个属性都会增加变量propsInA。

第二个循环对B做同样的事情,但这里变得更加复杂。首先,它检查A中是否存在该属性,或者如果deepequal返回true。这是我们检查的前两个片段发挥作用的地方。如果我们提供的属性相同,则此处使用的第一个片段返回true。第二个片段说"如果我们通过属性而不是函数,请停在这里"。这很重要,因为如果它的初始调用,这个函数只需要在这里继续。所有递归调用只需要使用第一部分。如果这两个中的任何一个返回false,我们将false返回到初始调用,因为我们知道A和B之间存在差异。

return propsInA == propsInB;

我们无法在这里回归,因为我们实际上并不知道B中是否有更少的属性。即使其他一切看起来都是一样的,我们也不能假设他们有相同数量的属性。作为最终检查,这确保了如果A中的属性数量等于B中的数量,我们将仅返回true

请随时让我进一步解释。

答案 2 :(得分:0)

关于此功能

  • 首先,该函数检查第一个参数是否等于第二个参数,然后返回true
  • typeof a! = "object" - 检查参数(a和b)的类型是否为对象,如果其中一个不是对象,则函数将以返回false结束。
  • 然后如果它通过了这个条件(a和b是对象),它将继续下一步 - 一个循环将遍历对象上的项目(a和b),并将它们计算propsInA因此,对于a和propsInB为b。
  • 下一步是检查参数上是否有项目,如果是,则返回false
  • 否则该函数将在propsInApropsInB之间进行比较,如果它们相同,则函数将以返回true结束,否则将返回false

答案 3 :(得分:0)

您的算法的行为如下:

  1. 如果ab被视为严格相等,请返回true

    如果其中一项适用,则

    ab被视为严格相等:

    • NaN
    • 外,它们的原始值相同
    • 他们是+0-0(或反之亦然)
    • 它们是相同的对象(相同的参考)。

    这是使用严格相等比较(===)运算符完成的。

  2. 如果ab或两者都不被视为对象,请返回false

    如果其中一个适用,

    o不被视为对象:

    • o是原始值
    • o属于Object类型,但有一个内部[[Call]]方法。也就是说,是一个可调用的对象,例如函数或HTML <object>元素。
    • o是一个不可调用的非标准异域对象,其typeof运算符返回的实现定义与"object&#34;`不同。

    这是使用typeof运算符完成的,该运算符返回一个包含值类型的字符串,但null和对象除外。由于typeof null === "object"a == null已被检查。

  3. 如果ab具有不同数量的可枚举属性(考虑自有属性和继承属性),请返回false

    这由propsInApropsInB计算。

  4. 如果b具有可枚举(自有或继承)属性但a没有(不可枚举或可枚举,拥有或继承),则不一定相同具有相同名称的b)属性,返回false

    这是迭代for (var prop in b)并检查prop in a

  5. 如果b具有可枚举(自有或继承)属性,deepEqual算法的值与a中相同属性的值不同,则返回{ {1}}。

    这是迭代false并检查for (var prop in b)

  6. 否则,请返回deepEqual(a[prop], b[prop])

  7. 我认为这不是一个好的算法。例如,它认为true{}Object.prototype都是平等的,但我不会这样说。