初学者- Javascript中的深度比较

Beginner - Deep comparaison in Javascript

本文关键字:深度 比较 Javascript 初学者      更新时间:2023-09-26

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

嗯,我正在阅读雄辩的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和....假!

输出如下:

========
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

有两件事我不明白:

  • 为什么总是转到"检查属性"而从来不转到"检查对象"?{is: "an"}是一个对象,不是吗?
  • 为什么"obj1[prop]!"=obj2[prop]" true,尽管,根据日志,它们都等于:{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循环(for (var prop in b))搞糊涂了…

编辑:非常感谢大家的回答!我不知道该接受哪一个,因为它们都对我帮助很大:-/

prop(在您的for (prop in obj)循环中)不是一个值-它是一个键(MDN上的for in循环)。当使用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)

边注: javascript的一个好习惯是使用===(严格比较)运算符而不是==(抽象比较)。为什么?因为前者不会隐式地将比较值转换为其他类型。Javascript的类型转换不是那么明显,所以最好坚持使用更可预测的操作符。在JS中使用严格比较通常是更安全的比较方式。

您可以在MDN上阅读更多关于该主题的内容。

这一行不对:

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

prop是属性的键,它总是一个字符串,而不是属性的值。应该是:

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

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

为什么"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…和…
==忽略数据类型,如"3" == 3 // true