我需要重构我的程序以获取JSON obj,将其存储在某处,进行一系列更改,然后比较这两个对象以查看已更改,删除和添加的内容。
我不确定如何在JS中执行此操作,那么有人可以建议在Angular中执行此操作(对象比较部分)吗?否则,我将不得不对我的程序运行/从后端尝试它的方式进行大量更改。感谢任何帮助。
答案 0 :(得分:2)
对象比较的唯一内置操作是==
/ ===
等于运算符,它们使用引用相等:A是B,而不是A等于B.
您想要的是描述两个对象之间差异的更改描述符列表。
正如评论中所指出的,这需要使用参考和存在检查的混合物对对象进行递归遍历。
以下算法是一个想法的快速实现。遍历对象,并使用对象列表描述其更改。就像对象本身一样,更改是嵌套的,但是根据它们在对象中的位置具有唯一的id(因此它可以被展平)。
function diff(a, b, namespace) {
namespace = (namespace || '') + '.';
var keysInA = Object.keys(a),
keysInB = Object.keys(b);
var diffA = keysInA.reduce(function(changes, key) {
var ns = namespace + key;
if(typeof b[key] == 'undefined') {
return changes.concat([{ type: 'DELETED', id: ns }]);
}
if(a[key] !== b[key]) {
return changes.concat([{ type: 'CHANGED', id: ns }]);
}
if(typeof a[key] == b[key] == 'object') {
return diff(a[key], b[key], ns);
}
return changes;
}, []);
var diffB = keysInB.reduce(function(changes, key) {
var ns = namespace + key;
if(typeof a[key] == 'undefined') {
return changes.concat([{ type: 'ADDED', id: ns }]);
}
return changes;
}, []);
return diffA.concat(diffB);
}
例如,我们采用对象的原始状态。
var a = { a: 1, b: 2, c: 3 };
新州。
var b = { a: 2, c: 3, d: 5 };
然后使用diff
函数运行它们。
diff(a, b);
返回更改列表。
[
{ id: '.a', type: 'CHANGED' },
{ id: '.b', type: 'DELETED' },
{ id: '.d', type: 'ADDED' }
]
显然,您必须调整此算法,使其符合您构成变更的标准。您可能希望查看deep equality,而不是整体比较参考文献。
答案 1 :(得分:0)
我将在这里添加我对Dan的建议的实现,以防它有助于想要看到实际实现的人:
var propertiesToIgnore = ['.indexesTracked', '.notInSyncWithDb', '.date', '.details.updatedAt', '.autoLoadLocalStorage', '.deletionQueue']; //these are extraneous properties added to project that should not be represented in interface (and not tracked)
var keysToIgnore = ['addAllDatacuts', 'datacutNames']; // this just looks at the property rather than the above which matches from the project root
function diff(a, b, namespace, firstCall) {
namespace = firstCall ? (namespace || '') : (namespace || '') + '.';
var keysInA = Object.keys(a),
keysInB = Object.keys(b);
var diffA = keysInA.reduce(function(changes, key) {
var ns = namespace + key;
if (propertiesToIgnore.indexOf(ns) !== -1 || keysToIgnore.indexOf(key) !== -1) {
return changes;
}
if (key == '$$hashKey') {
return changes;
}
if (angular.equals(a[key], b[key])) { // whole chain is equal so I do not need to iterate over this branch
return changes;
}
if (typeof b[key] == 'undefined') {
return changes.concat([{ type: 'DELETED', id: ns }]);
}
if (a[key] !== b[key] && (typeof b[key] !== 'object' || typeof a[key] !== 'object')) {
return changes.concat([{ type: 'UPDATED', id: ns }]);
}
if (typeof b[key] === 'object' && typeof a[key] === 'object') {
return changes.concat(diff(a[key], b[key], ns));
}
if (a[key] === null || b[key] === null) { // avoids values that are null as js considers null an object
return changes;
}
if(typeof a[key] == 'object' && typeof b[key] == 'object' && typeof a[key].getMonth !== 'function' && typeof b[key].getMonth !== 'function') { // last part necessary to make sure it is not a date object
return diff(a[key], b[key], ns);
}
return changes;
}, []);
var diffB = keysInB.reduce(function(changes, key) {
var ns = namespace + key;
if (propertiesToIgnore.indexOf(ns) !== -1 || keysToIgnore.indexOf(key) !== -1) {
return changes;
}
if (key == '$$hashKey') {
return changes;
}
if (typeof a[key] == 'undefined') {
return changes.concat([{ type: 'ADDED', id: ns }]);
}
return changes;
}, []);
return diffA.concat(diffB);
}
$scope.changes = diff(dbData, $scope.project, '');