我正在查看 Eloquent Javascript 练习中的deepEqual
比较函数。我认为我可以通过将检查对象存在的if
语句和值相等性检查移动到第一个for..in
循环而不是第二个循环来改进建议解决方案。
我的理由是,如果对象没有匹配的属性或者它们的值不同而不是等待在第二个循环中这样做,它将允许检查更早失败。
此更改无效 。 This jsbin demonstrates the issue,这是代码:
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...?
注释掉snippet中的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
从我所看到的情况来看,
for..in
参数的b
在这里很早就开始了,并影响了循环的后续运行 价值。
我错过了什么?
我认为应该的方式
据我了解,第3个日志应运行如下:
CALL:
deepEqual({here: {is: "an"}, object: 2},{here: {is: "an"}, object: 2})
(a === b)
→false
,a
和b
是对象,续pA
和pB
设为0 启动for..in
循环
pA
为1,p
为here
here
位于b
,因此必须致电:deepEqual({is: "an"}, {is: "an"})
for..in
循环
pA
为1,p
为is
here
位于b
,因此必须致电:deepEqual("an", "an")
if
失败,开始下一轮循环:pA
为2,p
为object
object
位于b
,因此必须致电:deepEqual(2, 2)
for..in
循环
pA
为1,p
为is
here
位于b
,因此必须致电:deepEqual(a['is'], b['is'])
此时pA
为2
剩下要做的就是迭代b
pB
应为2
返回(pA === pB)
,与return 2===2
相同,即return true
目前正在退出false
。
答案 0 :(得分:3)
你被JavaScript的Implicit Globals
所困扰问题在于这一行:
var pA = pB = 0;
当解构为多行时,它看起来像:
pB = 0;
var pA = pB;
这意味着pB
未与var
一起声明,因此是全局变量,而不是deepEqual
的本地变量。这意味着它通过计算保留其值,因此具有错误的值。
您的函数返回false
,因为对于具有2个属性的顶级对象级别,pB
最终会使用值3
而不是2
,因为它会记住内部的计数level,有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}));
这是related question值得一试。