Deep comparison of objects/arrays
Possible Duplicate:
How do you determine equality for two JavaScript objects?
Object comparison in JavaScript
如果我有两个数组或对象并想比较它们,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | object1 = [ { shoes: [ 'loafer', 'penny' ] }, { beers: [ 'budweiser', 'busch' ] } ] object2 = [ { shoes: [ 'loafer', 'penny' ] }, { beers: [ 'budweiser', 'busch' ] } ] object1 == object2 // false |
如果您收到服务器的响应并试图查看它是否发生了更改,这可能会很烦人。
更新:为了响应原始建议周围的评论和担忧(比较2个JSON字符串),您可以使用以下函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | function compareObjects(o, p) { var i, keysO = Object.keys(o).sort(), keysP = Object.keys(p).sort(); if (keysO.length !== keysP.length) return false;//not the same nr of keys if (keysO.join('') !== keysP.join('')) return false;//different keys for (i=0;i<keysO.length;++i) { if (o[keysO[i]] instanceof Array) { if (!(p[keysO[i]] instanceof Array)) return false; //if (compareObjects(o[keysO[i]], p[keysO[i]] === false) return false //would work, too, and perhaps is a better fit, still, this is easy, too if (p[keysO[i]].sort().join('') !== o[keysO[i]].sort().join('')) return false; } else if (o[keysO[i]] instanceof Date) { if (!(p[keysO[i]] instanceof Date)) return false; if ((''+o[keysO[i]]) !== (''+p[keysO[i]])) return false; } else if (o[keysO[i]] instanceof Function) { if (!(p[keysO[i]] instanceof Function)) return false; //ignore functions, or check them regardless? } else if (o[keysO[i]] instanceof Object) { if (!(p[keysO[i]] instanceof Object)) return false; if (o[keysO[i]] === o) {//self reference? if (p[keysO[i]] !== p) return false; } else if (compareObjects(o[keysO[i]], p[keysO[i]]) === false) return false;//WARNING: does not deal with circular refs other than ^^ } if (o[keysO[i]] !== p[keysO[i]])//change !== to != for loose comparison return false;//not the same value } return true; } |
但在很多情况下,在我看来,这并不难:
1 | JSON.stringify(object1) === JSON.stringify(object2); |
如果字符串化对象相同,则它们的值相同。
为了完整起见:
试图比较仅包含函数的2个对象将导致
1 2 3 4 | JSON.stringify({foo: function(){return 1;}}) === JSON.stringify({foo: function(){ return -1;}}); //evaulutes to: '{}' === '{}' //is true, of course |
对于对象/函数的深入比较,您必须使用libs或编写自己的函数,并克服JS对象都是引用的事实,因此在比较
正如@A-J在评论中指出的那样:
1 | JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1}); |
是
创建的每个对象,每次被修改,V8创建一个新的隐藏C++类(排序)。如果对象x有一个属性
然而,在A-J所指出的例子中,两个对象的字符串化是不同的。怎么会?简单地说,这些对象永远不会同时存在:
1 | JSON.stringify({a: 1, b: 2}) |
这是一个函数调用,需要先将其解析为结果值,然后才能将其与右侧操作数进行比较。第二个对象文本还不在表中。对象被串化,并且外显式被解析为字符串常量。对象文本未在任何地方被引用,已标记为垃圾收集。之后,右侧操作数(
一切都很好,但也需要考虑的是,JS引擎现在比以前复杂得多。同样,我不是V8专家,但我认为A-J的代码片段正在进行大量优化是合理的,因为代码优化到:
1 | "{"b":2,"a":1}" ==="{"a":1,"b":2}" |
基本上省略了
作为下划线混合:
在咖啡脚本中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | _.mixin deepEquals: (ar1, ar2) -> # typeofs should match return false unless (_.isArray(ar1) and _.isArray(ar2)) or (_.isObject(ar1) and _.isObject(ar2)) #lengths should match return false if ar1.length != ar2.length still_matches = true _fail = -> still_matches = false _.each ar1, (prop1, n) => prop2 = ar2[n] return if prop1 == prop2 _fail() unless _.deepEquals prop1, prop2 return still_matches |
在javascript中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | _.mixin({ deepEquals: function(ar1, ar2) { var still_matches, _fail, _this = this; if (!((_.isArray(ar1) && _.isArray(ar2)) || (_.isObject(ar1) && _.isObject(ar2)))) { return false; } if (ar1.length !== ar2.length) { return false; } still_matches = true; _fail = function() { still_matches = false; }; _.each(ar1, function(prop1, n) { var prop2; prop2 = ar2[n]; if (prop1 !== prop2 && !_.deepEquals(prop1, prop2)) { _fail(); } }); return still_matches; } }); |