Comme il a été demandé, voici une fonction de comparaison d'objets récursive. Et un peu plus. En supposant que l'utilisation principale d'une telle fonction est l'inspection d'objets, j'ai quelque chose à dire. Une comparaison approfondie complète est une mauvaise idée lorsque certaines différences ne sont pas pertinentes. Par exemple, une comparaison approfondie aveugle dans les assertions TDD rend les tests inutiles fragiles. Pour cette raison, je voudrais introduire un diff partiel beaucoup plus précieux . Il s'agit d'un analogue récursif d'une contribution précédente à ce fil. Il ignore les clés non présentes dans un
var bdiff = (a, b) =>
_.reduce(a, (res, val, key) =>
res.concat((_.isPlainObject(val) || _.isArray(val)) && b
? bdiff(val, b[key]).map(x => key + '.' + x)
: (!b || val != b[key] ? [key] : [])),
[]);
BDiff permet de vérifier les valeurs attendues tout en tolérant d'autres propriétés, ce qui est exactement ce que vous souhaitez pour une inspection automatique . Cela permet de construire toutes sortes d'assertions avancées. Par exemple:
var diff = bdiff(expected, actual);
// all expected properties match
console.assert(diff.length == 0, "Objects differ", diff, expected, actual);
// controlled inequality
console.assert(diff.length < 3, "Too many differences", diff, expected, actual);
Revenons à la solution complète. Construire un diff traditionnel complet avec bdiff est trivial:
function diff(a, b) {
var u = bdiff(a, b), v = bdiff(b, a);
return u.filter(x=>!v.includes(x)).map(x=>' < ' + x)
.concat(u.filter(x=>v.includes(x)).map(x=>' | ' + x))
.concat(v.filter(x=>!u.includes(x)).map(x=>' > ' + x));
};
L'exécution de la fonction ci-dessus sur deux objets complexes produira quelque chose de similaire à ceci:
[
" < components.0.components.1.components.1.isNew",
" < components.0.cryptoKey",
" | components.0.components.2.components.2.components.2.FFT.min",
" | components.0.components.2.components.2.components.2.FFT.max",
" > components.0.components.1.components.1.merkleTree",
" > components.0.components.2.components.2.components.2.merkleTree",
" > components.0.components.3.FFTResult"
]
Enfin, afin d'avoir un aperçu de la façon dont les valeurs diffèrent, nous pouvons vouloir évaluer directement () la sortie diff. Pour cela, nous avons besoin d'une version plus laide de bdiff qui génère des chemins syntaxiquement corrects:
// provides syntactically correct output
var bdiff = (a, b) =>
_.reduce(a, (res, val, key) =>
res.concat((_.isPlainObject(val) || _.isArray(val)) && b
? bdiff(val, b[key]).map(x =>
key + (key.trim ? '':']') + (x.search(/^\d/)? '.':'[') + x)
: (!b || val != b[key] ? [key + (key.trim ? '':']')] : [])),
[]);
// now we can eval output of the diff fuction that we left unchanged
diff(a, b).filter(x=>x[1] == '|').map(x=>[x].concat([a, b].map(y=>((z) =>eval('z.' + x.substr(3))).call(this, y)))));
Cela produira quelque chose de similaire à ceci:
[" | components[0].components[2].components[2].components[2].FFT.min", 0, 3]
[" | components[0].components[2].components[2].components[2].FFT.max", 100, 50]
Licence MIT;)