2017-02-06 53 views
2

我正在查看deepEqual比較功能Eloquent Javascript練習。我認爲我可以通過將if語句檢查對象存在和值相等性檢查到第一個for..in循環而不是第二個循環來改進建議的解決方案。已修改deepEqual函數不起作用

我的推理是,如果對象沒有匹配的屬性或者它們的值不同,而不是在第二個循環中等待,它會允許檢查提前失敗。

的變化沒有工作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...? 

註釋掉的代碼片段調用的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..inb參數在此處開始並影響後續運行的循環,具有正確的 值。

我錯過了什麼?


我認爲它的方式應該工作

據我瞭解,第三日誌應該運行如下:

CALL:

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

  • (a === b)false
  • ab是對象,繼續
  • 設置pApB至0
  • 開始for..in

    1. pA是1,phere
      • hereb於是紛紛致電:
      • deepEqual({is: "an"}, {is: "an"})
      • 他們都是對象,所以去:
      • 開始for..in
        • pA爲1, pis
          • hereb於是紛紛致電:
          • deepEqual("an", "an")
      • < < < < < < < < < < < <返回true!
      • if失敗,啓動循環的下一次迭代:
    2. pA是2,pobject
      • object是在b所以必須調用:
      • deepEqual(2, 2)
      • th ey're兩個對象,所以還是:
      • 開始for..in
        • pA爲1,pis
          • hereb於是紛紛致電:
          • deepEqual(a['is'], b['is'])
      • < < < < < < < < < < < <返回true!
  • 此時pA是2

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

  • pB應該是2

返回(pA === pB),與相同210,這是return true

它目前正在註銷false

回答

3

你已經通過JavaScript的Implicit Globals

問題咬傷是此行

var pA = pB = 0; 

當解構爲多行,它看起來像:

pB = 0; 
var pA = pB; 

這意味着pB不申報與var,因此是全球變量,而不是本地變量deepEqual。這意味着它通過計算保留其價值,因此具有錯誤的價值。

你的函數返回false因爲pB,因爲它從內水平,其中有1個屬性{ is: "an" }記住其計數與2個屬性中的頂層對象電平結束了一個值3代替2。另外兩個測試工作,因爲他們只檢查單一級別的屬性。

如果您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

+1

啊哈!謝謝!我有一個暗示,這與此有關。我想我必須一直試圖做到這一點:'var pA,pB = pA = 0;'。我的推理是否將'if'條件移至第一個循環聲音? – Pineda

+1

@Pineda不客氣。至於在任何一個循環中都有「if」條件,它不會真正改變一般(基於最壞情況)的效率。您的更改可能有助於某些特定情況,但會導致其他情況效率降低。基本上你所做的就是使'pA'更重要,即'pB',但如果有人通過反向參數比初始不變的方法更好。 – nem035

+1

我現在看到了。非常感謝您的幫助。 – Pineda