Như đã hỏi, đây là một hàm so sánh đệ quy. Và một chút nữa. Giả sử rằng việc sử dụng chính của chức năng đó là kiểm tra đối tượng, tôi có vài điều muốn nói. Hoàn toàn so sánh sâu là một ý tưởng tồi khi một số khác biệt là không liên quan. Ví dụ, so sánh sâu mù quáng trong các xác nhận TDD làm cho các xét nghiệm trở nên giòn không cần thiết. Vì lý do đó, tôi muốn giới thiệu một phần khác biệt có giá trị hơn nhiều . Nó là một tương tự đệ quy của một đóng góp trước đó cho chủ đề này. Nó bỏ qua các phím không có mặt trong một
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 cho phép kiểm tra các giá trị dự kiến trong khi dung sai các thuộc tính khác, đó chính xác là những gì bạn muốn để kiểm tra tự động . Điều này cho phép xây dựng tất cả các loại xác nhận nâng cao. Ví dụ:
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);
Trở lại với giải pháp hoàn chỉnh. Xây dựng một khác biệt truyền thống đầy đủ với bdiff là tầm thường:
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));
};
Chạy chức năng trên trên hai đối tượng phức tạp sẽ tạo ra một cái gì đó tương tự như sau:
[
" < 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"
]
Cuối cùng, để có cái nhìn tổng quát về các giá trị khác nhau như thế nào, chúng ta có thể muốn trực tiếp eval () đầu ra khác. Vì thế, chúng ta cần một phiên bản bdiff xấu hơn tạo ra các đường dẫn chính xác về mặt cú pháp:
// 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)))));
Điều đó sẽ tạo ra một cái gì đó tương tự như thế này:
[" | components[0].components[2].components[2].components[2].FFT.min", 0, 3]
[" | components[0].components[2].components[2].components[2].FFT.max", 100, 50]
Giấy phép MIT;)