2016-05-08 140 views
0

考慮下面的函數的藍圖,它試圖比較兩個對象的比較:對象與遞歸函數

function objectCompare(a,b,path){ 
    for (var prop in a) { 
     path=prop; 
     if (a.hasOwnProperty(prop) && !(b.hasOwnProperty(prop))) { 
       ... 
      return false; 
     } 
     ... 
     if (detectType(a[prop])==='Object'){ 
      if (!objectCompare(a[prop],b[prop],path)) 
       return false; 
     } 
     ... 
    } 
     return true; 
} 

detectType是我自己的函數檢查一個變量的類型。我的問題是,每次我們有遞歸調用時,我都想豐富變量path。然而,在當遞歸調用結束的同時,path必須遍歷初始對象的剩餘財產的名稱,而不濃... 試想以下對象:

var Obj1 = { 
     p1: 's', 
     p2: { 
      p1: {a: { propA: 'a', propB: 'b' }}, 
      p2: 'g', 
     } 
     }; 

var Obj2 = { 
     p1: 's', 
     p2: { 
      p1: {a: { propA: 'a', propB: 'c' }}, 
      p2: 'g', 
     } 
     }; 

我想path時功能objectCompare返回具有以下值:p2.p1.a.propB即,使兩個對象不同的點。我如何實現這一目標?

+0

現在已經有很多的問題,並約在Javascript對象比較的答案。 – trincot

+0

@ILIAS,如果所有對象都具有嚴格的屬性順序,則可以以非常簡單的方式完成比較 – RomanPerekhrest

+0

您能否給我一些提示? –

回答

1

您必須將當前密鑰添加到路徑並將新路徑傳遞給遞歸調用。試想一下:

console.info=function(x){document.write('<pre>'+JSON.stringify(x,0,3)+'</pre>')} 
 
//-- 
 

 
// compare: return path if a,b are different, null otherwise 
 

 
function compare(a, b, path) { 
 

 
    var ta = typeof a, 
 
     tb = typeof b; 
 

 
    // different types - fail 
 
    
 
    if (ta !== tb) { 
 
     return path; 
 
    } 
 
    
 
    // scalars - null if equal, path if not 
 

 
    if (ta !== 'object') { 
 
     return a === b ? null : path; 
 
    } 
 
    
 
    // make a set of keys from both objects 
 

 
    var keys = Object.keys(a).concat(Object.keys(b)).filter(function(x, i, self) { 
 
     return self.indexOf(x) === i; 
 
    }); 
 

 
    // for each key in set, compare values 
 
    
 
    var res = null; 
 

 
    keys.some(function(k) { 
 
     return res = compare(a[k], b[k], path.concat(k)); 
 
    }); 
 

 
    // return null or the first failed path 
 
    
 
    return res; 
 
} 
 

 
// 
 

 
var Obj1 = { 
 
     p1: 's', 
 
     p2: { 
 
      p1: {a: { propA: 'a', propB: 'b' }}, 
 
      p2: 'g', 
 
     } 
 
     }; 
 

 
var Obj2 = { 
 
     p1: 's', 
 
     p2: { 
 
      p1: {a: { propA: 'a', propB: 'c' }}, 
 
      p2: 'g', 
 
     } 
 
     }; 
 

 

 

 
var res = compare(Obj1, Obj2, []) 
 
console.info(res);

+0

了不起的解決方案!非常感謝你 –

+0

謝謝!它需要更多的工作才能正確處理null值(如在'compare({a:null},{b:null})')中。 – georg

+0

我可以問你一個大忙嗎?是否有可能訪問您的一些Javascript項目?你的代碼風格很壯觀。我想從他們那裏學習和學習,因爲我想在英國找到工作,我必須改善我的代碼風格。謝謝 –

0

圖書館deep-diff做你所需要的。

上面參考呈現該示例中的代碼:

var diff = require('deep-diff').diff; 

var lhs = { 
    name: 'my object', 
    description: 'it\'s an object!', 
    details: { 
     it: 'has', 
     an: 'array', 
     with: ['a', 'few', 'elements'] 
    } 
}; 

var rhs = { 
    name: 'updated object', 
    description: 'it\'s an object!', 
    details: { 
     it: 'has', 
     an: 'array', 
     with: ['a', 'few', 'more', 'elements', { than: 'before' }] 
    } 
}; 

var differences = diff(lhs, rhs); 

上面的代碼段將導致以下結構描述不同之處:

[ { kind: 'E', 
    path: [ 'name' ], 
    lhs: 'my object', 
    rhs: 'updated object' }, 
    { kind: 'E', 
    path: [ 'details', 'with', 2 ], 
     lhs: 'elements', 
     rhs: 'more' }, 
    { kind: 'A', 
    path: [ 'details', 'with' ], 
    index: 3, 
    item: { kind: 'N', rhs: 'elements' } }, 
    { kind: 'A', 
    path: [ 'details', 'with' ], 
    index: 4, 
    item: { kind: 'N', rhs: { than: 'before' } } } ] 

值得注意的是,path屬性很像所需輸出。

+0

我想構建我自己的功能,而不是使用庫,我有'path'這個特定的問題。 –