2016-05-08 103 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'这个特定的问题。 –