Seperti yang ditanyakan, inilah fungsi perbandingan objek rekursif. Dan sedikit lagi. Dengan asumsi bahwa penggunaan utama dari fungsi tersebut adalah inspeksi objek, saya punya sesuatu untuk dikatakan. Perbandingan mendalam yang lengkap adalah ide yang buruk ketika beberapa perbedaan tidak relevan. Sebagai contoh, perbandingan yang dalam pada pernyataan TDD membuat tes tidak rapuh. Untuk alasan itu, saya ingin memperkenalkan diff parsial yang jauh lebih berharga . Ini adalah analog rekursif dari kontribusi sebelumnya ke utas ini. Ini mengabaikan kunci yang tidak ada dalam a
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 memungkinkan pengecekan nilai yang diharapkan sambil mentoleransi properti lain, yang persis seperti yang Anda inginkan untuk inspeksi otomatis . Ini memungkinkan membangun semua jenis pernyataan tingkat lanjut. Sebagai contoh:
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);
Kembali ke solusi lengkap. Membangun diff tradisional penuh dengan bdiff itu sepele:
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));
};
Menjalankan fungsi di atas pada dua objek kompleks akan menghasilkan sesuatu yang mirip dengan ini:
[
" < 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"
]
Akhirnya, untuk melihat bagaimana perbedaan nilai, kita mungkin ingin langsung mengevaluasi () output diff. Untuk itu, kita memerlukan versi jelek dari bdiff yang menghasilkan jalur yang benar secara sintaksis:
// 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)))));
Itu akan menghasilkan sesuatu yang mirip dengan ini:
[" | components[0].components[2].components[2].components[2].FFT.min", 0, 3]
[" | components[0].components[2].components[2].components[2].FFT.max", 100, 50]
Lisensi MIT;)