jQuery函数,用于计算两个JavaScript对象之间的差异
jQuery function to compute the difference between two JavaScript objects
我有一个基于 AJAX 的丰富 Web 应用程序,它使用 JQuery + Knockout。我有一个JQuery插件,它包装了我的Knockout视图模型以公开实用程序方法,如.reset(),.isDirty()等。
我有一个名为 .setBaseline() 的方法,它基本上是在填充数据模型后(通过映射插件)拍摄数据的快照。然后,我可以使用此快照快速确定模型是否已更改。
我正在寻找的是某种通用函数,它可以返回一个对象,该对象表示两个 2 JavaScript 对象之间的差异,其中一个对象被认为是主对象。
例如,假设这是我的快照:
var snapShot = {
name: "Joe",
address: "123 Main Street",
age: 30,
favoriteColorPriority: {
yellow: 1,
pink: 2,
blue: 3
}
};
然后假设实时数据如下所示:
var liveData = {
name: "Joseph",
address: "123 Main Street",
age: 30,
favoriteColorPriority: {
yellow: 1,
pink: 3,
blue: 2
}
};
我想要一个返回以下内容的.getChanges(snapShot,liveData)实用程序函数:
var differences = {
name: "Joseph",
favoriteColorPriority: {
pink: 3,
blue: 2
}
};
我希望 _.underscore 库可能有这样的东西,但我找不到任何似乎像这样工作的东西。
我不认为下划线中有这样的函数,但很容易实现自己:
function getChanges(prev, now) {
var changes = {};
for (var prop in now) {
if (!prev || prev[prop] !== now[prop]) {
if (typeof now[prop] == "object") {
var c = getChanges(prev[prop], now[prop]);
if (! _.isEmpty(c) ) // underscore
changes[prop] = c;
} else {
changes[prop] = now[prop];
}
}
}
return changes;
}
或
function getChanges(prev, now) {
var changes = {}, prop, pc;
for (prop in now) {
if (!prev || prev[prop] !== now[prop]) {
if (typeof now[prop] == "object") {
if(c = getChanges(prev[prop], now[prop]))
changes[prop] = c;
} else {
changes[prop] = now[prop];
}
}
}
for (prop in changes)
return changes;
return false; // false when unchanged
}
这不适用于数组(或任何其他非普通对象)或结构不同的对象(删除、对象类型更改的基元)。
发布我自己的答案,以便人们可以看到也适用于数组的最终实现。在下面的代码中,"um"是我的命名空间,我也使用了Underscore.js中的_.isArray()和_.isObject方法。
查找"_KO"的代码用于跳过对象中存在的 Knockout.js 成员。
// This function compares 'now' to 'prev' and returns a new JavaScript object that contains only
// differences between 'now' and 'prev'. If 'prev' contains members that are missing from 'now',
// those members are *not* returned. 'now' is treated as the master list.
um.utils.getChanges = function (prev, now) {
var changes = {};
var prop = {};
var c = {};
//-----
for (prop in now) { //ignore jslint
if (prop.indexOf("_KO") > -1) {
continue; //ignore jslint
}
if (!prev || prev[prop] !== now[prop]) {
if (_.isArray(now[prop])) {
changes[prop] = now[prop];
}
else if (_.isObject(now[prop])) {
// Recursion alert
c = um.utils.getChanges(prev[prop], now[prop]);
if (!_.isEmpty(c)) {
changes[prop] = c;
}
} else {
changes[prop] = now[prop];
}
}
}
return changes;
};
我在我的项目中使用 JsonDiffPatch 来查找增量,通过网络传输它,然后在另一端修补对象以获得确切的副本。它非常易于使用并且效果非常好。
它也适用于数组!
jQuery.isEmptyObject() 的解决方案
这重新设计了上面的getChanges(prev,now)解决方案。它也应该适用于不同类型的对象,以及当 prev[prop] 未定义时(导致 now[prop])
function getChanges(prev, now)
{
// sanity checks, now and prev must be an objects
if (typeof now !== "object")
now = {};
if (typeof prev !== "object")
return now;
var changes = {};
for (var prop in now) {
// if prop is new in now, add it to changes
if (!prev || !prev.hasOwnProperty(prop) ) {
changes[prop] = now[prop];
continue;
}
// if prop has another type or value (different object or literal)
if (prev[prop] !== now[prop]) {
if (typeof now[prop] === "object") {
// prop is an object, do recursion
var c = getChanges(prev[prop], now[prop]);
if (!$.isEmptyObject(c))
changes[prop] = c;
} else {
// now[prop] has different but literal value
changes[prop] = now[prop];
}
}
}
// returns empty object on none change
return changes;
}
不需要为此使用 jquery。我最近写了一个模块来做到这一点:https://github.com/Tixit/odiff。下面是一个示例:
var a = [{a:1,b:2,c:3}, {x:1,y: 2, z:3}, {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]
var diffs = odiff(a,b)
/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
{type: 'set', path:[1,'y'], val: '3'},
{type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/
在 odiff 的自述文件中,我列出了其他模块,如果您也想查看这些模块,我确定这些模块不符合我的需求。
基于上面的解决方案。此版本纠正了一个错误,原始解决方案未检测到某些更改。
getChanges = function (prev, now) {
var changes = {}, prop, pc;
for (prop in now) {
if (!prev || prev[prop] !== now[prop]) {
if (typeof now[prop] == "object") {
if (c = getChanges(prev[prop], now[prop]))
changes[prop] = c;
} else {
changes[prop] = now[prop];
}
}
}
for (prop in prev) {
if (!now || now[prop] !== prev[prop]) {
if (typeof prev[prop] == "object") {
if (c = getChanges(now[prop], prev[prop]))
changes[prop] = c;
} else {
changes[prop] = prev[prop];
}
}
}
return changes;
};
,如果now[prop]
是日期,则typeof now[prop] == "object"
为真。
而不是: typeof now[prop] == "object"
我使用过: Object.prototype.toString.call( now[prop] === "[object Object]")
- 面向对象JavaScript中的私有函数
- 对象 Javascript 中的标签无效 - 想要添加事件列表器
- 将字符串转换为对象 javascript/jquery
- 正在检查对象javascript中是否存在嵌套属性
- 时间-日期对象JavaScript getUTCMilliseconds
- 仅在对象(javascript)中解析值
- 使用对象(JavaScript或jQuery)填充选择下拉列表
- 引用另一个对象javascript中的对象
- 如何删除列表中的对象?Javascript nodejs和下划线
- 无法从日期对象javascript获取日期和月份
- 如何在if语句中使用对象-Javascript
- 对象javascript错误
- 对象Javascript的少数实例
- 位置对象Javascript
- 将字符串传递到对象javascript中
- 获取对象Javascript或jQuery的最后一个值
- 鼠标接近对象Javascript
- 这个mixins代码是书中的错误吗;面向对象JavaScript的原理”;
- 使用闭包编译器编写更好的面向对象JavaScript完整示例代码
- 访问对象javascript数组中的对象属性值