修改后的深度相等函数不起作用



我在查看Eloquent Javascript练习中的deepEqual比较函数。我想我可以通过将检查对象存在性和值相等检查的if语句移动到第一个for..in循环而不是第二个来改进建议的解决方案。

我的理由是,如果对象没有匹配的属性或它们的值不同,而不是在第二个循环中等待,那么检查就会提前失败

更改无效 。这个jsbin演示了这个问题,这是代码:

function deepEqual(a, b){
if(a === b) return true;
if(a === null || typeof a !== "object" ||
b === null || typeof b !== "object")
return false;
var pA = pB = 0;
//console.log('OBJECT detected vals:',a,b);
for(var p in a){
pA++;
//console.log('pA:'+pA, p, a, (p in b));
// MOVED THE IF STATEMENT INTO THIS LOOP INSTEAD OF THE
// SECOND LOOP BELOW
if(!(p in b) || !deepEqual(a[p], b[p]))  
return false;
}
for(var p in b){
pB++;
//console.log('pB:'+pB, p, b, (p in a));
//if(!(p in a) || !deepEqual(a[p], b[p]))
//return false;
}
return pA === pB;
}
var obj = {here: {is: "an"}, object: 2};
console.log(deepEqual(obj, obj));
// → true WORKS
console.log(deepEqual(obj, {here: 1, object: 2}));
// → false WORKS
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));
// → true, DOES NOT WORK, LOGS OUT FALSE...?

注释掉代码段中的console.log调用应该呈现以下输出:

console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));
OBJECT detected vals: Object {here: Object, object: 2} Object {here: Object, object: 2}
pA:1 here Object {here: Object, object: 2} true
OBJECT detected vals: Object {is: "an"} Object {is: "an"}
pA:1 is Object {is: "an"} true
pB:1 is Object {is: "an"} true<-- why is this being called here, pA loop hasn't finished???
pA:2 object Object {here: Object, object: 2} true
pB:2 here Object {here: Object, object: 2} true
pB:3 object Object {here: Object, object: 2} true

根据我所看到的,b参数的for..in在这里很早就开始了,并通过正确的值

我错过了什么


我认为应该工作的方式

据我所知,第三个日志应该运行如下:

呼叫:

deepEqual({here: {is: "an"}, object: 2},{here: {is: "an"}, object: 2})

  • (a === b)→CCD_ 8
  • ab是对象,继续
  • pApB设置为0
  • 启动for..in环路

    1. pA为1,phere
      • hereb中,因此必须呼叫:
      • deepEqual({is: "an"}, {is: "an"})
      • 它们都是物体,所以去吧:
      • 启动for..in循环
        • pA为1,pis
          • hereb中,因此必须呼叫:
          • deepEqual("an", "an")
      • <lt<lt<lt<lt<lt<lt;返回TRUE
      • if失败,开始循环的下一次迭代
    2. pA是2,pobject
      • objectb中,因此必须呼叫:
      • deepEqual(2, 2)
      • 它们都是物体,所以去吧:
      • 启动for..in循环
        • pA为1,pis
          • hereb中,因此必须拨打:
          • deepEqual(a['is'], b['is'])
      • <lt<lt<lt<lt<lt<lt;返回TRUE
  • 此时pA为2

  • 剩下要做的就是迭代b 中的道具

  • pB应为2

返回(pA === pB),与return 2===2相同,后者为return true

它当前正在注销false

您已经被JavaScript的隐式全局咬了一口

问题是这条线:

var pA = pB = 0;

当分解成多行时,它看起来像:

pB = 0;
var pA = pB;

这意味着pB没有用var声明,因此是全局变量,而不是deepEqual的局部变量。这意味着它通过计算保持其值,因此具有错误的值。

函数返回false,因为具有2个属性的顶级对象级别的pB最终会得到值3,而不是2,因为它会记住内部级别的计数,内部级别具有1个属性{ is: "an" }。另外两个测试之所以有效,是因为它们只检查单个级别的属性。

如果将pB设为局部变量,则一切正常:

function deepEqual(a, b) {
if (a === b) return true;
if (a === null || typeof a !== "object" ||
b === null || typeof b !== "object")
return false;
// make both variables local
var pA = 0;
var pB = 0;
for (var p in a) {
pA++;
if (!(p in b) || !deepEqual(a[p], b[p]))
return false;
}
for (var p in b) {
pB++;
}
return pA === pB;
}
var obj = {here: {is: "an"}, object: 2};
console.log(deepEqual(obj, {here: {is: "an"}, object: 2}));

这里有一个相关的问题值得一看。

最新更新