初学者 - Javascript中的深度比较

时间:2016-09-06 17:03:48

标签: javascript

免责声明:我是JS的初学者

我正在阅读Eloquent Javascript,其中一个练习就是对JS中的对象进行深入比较。

有些对象定义如下:

var obj = {here: {is: "an"}, object: 2};

你应该检查他们的内容是否相等。 然后有3个测试:

console.log(deepEqual(obj, obj)); // supposed to return true
console.log(deepEqual(obj, {here: 1, object: 2})); // supposed to return false
console.log(deepEqual(obj, {here: {is: "an"}, object: 2})); // supposed to return true

这是我对深度均等方法的实现。为了简化我假设对比的对象具有相同的结构,它们在现实生活中不会,但是我的方法应该返回false(我认为)

function deepEqual(obj1,obj2)
{
console.log("========");
  for(prop in obj1)
  {
    console.log(prop);
    if (typeof(prop)=="object" && prop!=null)
    {
        console.log("Inspecting object ", obj1[prop],obj2[prop]);
        if (!deepEqual(obj1[prop],obj2[prop]))
        {
        return false;
        }
    }
    else
    {
      console.log("Inspecting property ",prop,'[',obj1[prop],'][',obj2[prop],']');
      if (obj1[prop]!=obj2[prop])
      { 
        console.log("Different property");
        return false;
      }
    }
  }
  return true;
}

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

它分别返回true,false和.... false!

这是输出:

========
here
Inspecting property  here [ {is: "an"} ][ {is: "an"} ]
object
Inspecting property  object [ 2 ][ 2 ]
true
========
here
Inspecting property  here [ {is: "an"} ][ 1 ]
Different property
false
========
here
Inspecting property  here [ {is: "an"} ][ {is: "an"} ]
Different property
false

有两件事我不明白:

  • 为什么总是去“检查财产”而从不“检查对象”? {是:“an”}是一个对象不是吗?
  • 为什么表达式“obj1 [prop]!= obj2 [prop]”是真的,但根据日志,它们都等于:{is:“an”}?

仅供参考,本书的参考实施是:

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;
}

对我来说,第一个for循环只计算A中有多少属性? 我对第二个for循环感到困惑(对于(b中的var prop))尽管......

编辑:非常感谢答案!我不知道接受哪一个,因为两者都帮助了我很多: - /

3 个答案:

答案 0 :(得分:2)

prop(在您的for (prop in obj)循环中)不是值 - 它是一个键(for in loop on MDN)。使用for in循环时,您可以引用如下值:

for (var key in obj) {
    var value = obj[key];
}

至于第二个问题:

  

为什么表达式" obj1 [prop]!= obj2 [prop]"的确如此,   根据日志,它们都等于:{is:" an"}?

请注意,在比较两个对象(或任何其他非原始值)时,会将它们按引用进行比较,而不是按值进行比较:

var obj1 = { name: true };
var obj2 = { name: true };
obj1 === obj2;
-> false (obj1 and obj2 are different objects)

var obj3 = { name: true };
var obj4 = obj3;
obj3 === obj4;
-> true (obj4 is basically a reference to obj3)

旁注:JavaScrpt中的一个好习惯是使用===(严格比较)运算符而不是==(抽象比较)。为什么?因为前一个不会隐式地将比较值转换为其他类型。 Javascript的类型转换并不那么明显,因此坚持使用更可预测的运算符会更好。使用严格的比较通常是更安全的方式来比较JS中的东西。

您可以阅读有关on MDN主题的更多信息。

答案 1 :(得分:1)

这一行错了:

if (typeof(prop)=="object" && prop!=null)

prop是属性的键,它始终是字符串,而不是属性的值。它应该是:

if (typeof(obj1[prop])=="object" && obj1[prop]!=null)

答案 2 :(得分:0)

我有一个很好的类比可能有助于解决这个问题:

  

为什么表达式" obj1 [prop]!= obj2 [prop]"的确如此,   根据日志,它们都等于:{is:" an"}?

我和我的兄弟可以说我们有同一个母亲。

我和那边的那个人可以说我们有相同的车,因为我们都有一辆黑色丰田凯美瑞。

My Mother === My Brother's Mother  // true, she is really the same person.

My car === Guy's car               // false, looks the same but 2 different cars
obj !== {here: {is: "an"}, object: 2} // just looks the same

===是严格的平等,例如"3" === 3 // false ... AND ...
==忽略数据类型,例如"3" == 3 // true