2016-05-08 8 views
0

は、2つのオブジェクトを比較しようとすると、以下の機能の青写真を考えてみましょう:は再帰関数との比較をオブジェクト

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つまり、2つのオブジェクトを異なるものにする点。どうすればそれを達成できますか?

+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

ありがとう! 'compare({a:null}、{b:null})')のように、 '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'にあります –

関連する問題