严格的相等运算符将告诉您两个对象类型是否相等。但是,有没有办法判断两个对象是否相等,就像 Java中的哈希码值一样?
堆栈溢出问题JavaScript中是否存在某种hashCode函数?与这个问题相似,但需要更多的学术答案。上面的场景演示了为什么必须要有一个,而我想知道是否有任何等效的解决方案。
严格的相等运算符将告诉您两个对象类型是否相等。但是,有没有办法判断两个对象是否相等,就像 Java中的哈希码值一样?
堆栈溢出问题JavaScript中是否存在某种hashCode函数?与这个问题相似,但需要更多的学术答案。上面的场景演示了为什么必须要有一个,而我想知道是否有任何等效的解决方案。
为了比较简单键/值对对象实例的键,我使用:
function compareKeys(r1, r2) {
var nloops = 0, score = 0;
for(k1 in r1) {
for(k2 in r2) {
nloops++;
if(k1 == k2)
score++;
}
}
return nloops == (score * score);
};
比较密钥后,一个简单的附加for..in
循环就足够了。
复杂度为O(N * N),其中N为键的数量。
我希望/猜测我定义的对象不会包含超过1000个属性...
这是以上所有内容的补充,而不是替代。如果您需要快速浅比较对象,而无需检查额外的递归情况。这是一个镜头。
对此进行比较:1)拥有的属性数量相等,2)关键字名称相等,3)如果bCompareValues == true,则对应的属性值及其类型相等(三重相等)
var shallowCompareObjects = function(o1, o2, bCompareValues) {
var s,
n1 = 0,
n2 = 0,
b = true;
for (s in o1) { n1 ++; }
for (s in o2) {
if (!o1.hasOwnProperty(s)) {
b = false;
break;
}
if (bCompareValues && o1[s] !== o2[s]) {
b = false;
break;
}
n2 ++;
}
return b && n1 == n2;
}
我建议不要进行散列或序列化(如JSON解决方案所示)。如果需要测试两个对象是否相等,则需要定义相等的含义。可能是两个对象中的所有数据成员都匹配,或者可能是内存位置必须匹配(这意味着两个变量都引用了内存中的同一对象),或者可能是每个对象中只有一个数据成员必须匹配。
最近,我开发了一个对象,该对象的构造函数在每次创建实例时都会创建一个新的id(从1开始并以1递增)。该对象具有isEqual函数,该函数将该id值与另一个对象的id值进行比较,如果匹配则返回true。
在那种情况下,我将“等于”定义为id值匹配。假设每个实例都有一个唯一的ID,则可以用来执行这样的想法,即匹配对象也占据相同的内存位置。虽然这不是必需的。
我看到了意大利面的代码答案。不使用任何第三方库,这很容易。
首先,通过键的键名对两个对象进行排序。
let objectOne = { hey, you }
let objectTwo = { you, hey }
// If you really wanted you could make this recursive for deep sort.
const sortObjectByKeyname = (objectToSort) => {
return Object.keys(objectToSort).sort().reduce((r, k) => (r[k] = objectToSort[k], r), {});
}
let objectOne = sortObjectByKeyname(objectOne)
let objectTwo = sortObjectByKeyname(objectTwo)
然后只需使用字符串进行比较即可。
JSON.stringify(objectOne) === JSON.stringify(objectTwo)
我遇到了同样的问题,并决定编写自己的解决方案。但是因为我也想将数组与对象进行比较,反之亦然,所以我设计了一个通用解决方案。我决定将这些功能添加到原型中,但是可以轻松地将它们重写为独立功能。这是代码:
Array.prototype.equals = Object.prototype.equals = function(b) {
var ar = JSON.parse(JSON.stringify(b));
var err = false;
for(var key in this) {
if(this.hasOwnProperty(key)) {
var found = ar.find(this[key]);
if(found > -1) {
if(Object.prototype.toString.call(ar) === "[object Object]") {
delete ar[Object.keys(ar)[found]];
}
else {
ar.splice(found, 1);
}
}
else {
err = true;
break;
}
}
};
if(Object.keys(ar).length > 0 || err) {
return false;
}
return true;
}
Array.prototype.find = Object.prototype.find = function(v) {
var f = -1;
for(var i in this) {
if(this.hasOwnProperty(i)) {
if(Object.prototype.toString.call(this[i]) === "[object Array]" || Object.prototype.toString.call(this[i]) === "[object Object]") {
if(this[i].equals(v)) {
f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
}
}
else if(this[i] === v) {
f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
}
}
}
return f;
}
该算法分为两部分:equals函数本身和一个用于在数组/对象中查找属性的数字索引的函数。因为indexof仅查找数字和字符串,而没有对象,所以仅需要find函数。
可以这样称呼它:
({a: 1, b: "h"}).equals({a: 1, b: "h"});
该函数返回true或false,在这种情况下为true。该算法还允许在非常复杂的对象之间进行比较:
({a: 1, b: "hello", c: ["w", "o", "r", "l", "d", {answer1: "should be", answer2: true}]}).equals({b: "hello", a: 1, c: ["w", "d", "o", "r", {answer1: "should be", answer2: true}, "l"]})
上面的示例将返回true,即使属性具有不同的顺序。需要注意的一个小细节:此代码还检查两个变量的相同类型,因此“ 3”与3不同。
ES6:我能完成的最少代码是这样。它通过对所有对象进行字符串化来进行深度比较,唯一的限制是没有方法或符号可以进行比较。
const compareObjects = (a, b) => {
let s = (o) => Object.entries(o).sort().map(i => {
if(i[1] instanceof Object) i[1] = s(i[1]);
return i
})
return JSON.stringify(s(a)) === JSON.stringify(s(b))
}
console.log(compareObjects({b:4,a:{b:1}}, {a:{b:1},b:4}));
比较对象,数组,字符串,整数等所有内容的最简单和逻辑的解决方案
JSON.stringify({a: val1}) === JSON.stringify({a: val2})
注意:
val1
并val2
用您的对象在Node.js中,您可以使用其native require("assert").deepStrictEqual
。更多信息:http :
//nodejs.org/api/assert.html
例如:
var assert = require("assert");
assert.deepStrictEqual({a:1, b:2}, {a:1, b:3}); // will throw AssertionError
另一个返回true
/ false
而不是返回错误的示例:
var assert = require("assert");
function deepEqual(a, b) {
try {
assert.deepEqual(a, b);
} catch (error) {
if (error.name === "AssertionError") {
return false;
}
throw error;
}
return true;
};
如果方便使用深层复制功能,则可以在匹配属性顺序时使用以下技巧继续使用JSON.stringify
:
function equals(obj1, obj2) {
function _equals(obj1, obj2) {
return JSON.stringify(obj1)
=== JSON.stringify($.extend(true, {}, obj1, obj2));
}
return _equals(obj1, obj2) && _equals(obj2, obj1);
}
演示:http : //jsfiddle.net/CU3vb/3/
理由:
由于的属性obj1
会一一复制到克隆中,因此将保留其在克隆中的顺序。而且,当将的属性obj2
复制到克隆中时,由于已经存在的属性obj1
将被简单地覆盖,因此它们在克隆中的顺序将被保留。
如果使用的是JSON库,则可以将每个对象编码为JSON,然后比较结果字符串是否相等。
var obj1={test:"value"};
var obj2={test:"value2"};
alert(JSON.encode(obj1)===JSON.encode(obj2));
注意:尽管此答案在许多情况下都有效,但正如一些人在评论中指出的那样,由于多种原因,这是有问题的。在几乎所有情况下,您都想找到一个更强大的解决方案。
您是否要测试两个对象是否相等?即:它们的属性是否相等?
如果是这种情况,您可能已经注意到这种情况:
var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"
您可能需要执行以下操作:
function objectEquals(obj1, obj2) {
for (var i in obj1) {
if (obj1.hasOwnProperty(i)) {
if (!obj2.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
}
for (var i in obj2) {
if (obj2.hasOwnProperty(i)) {
if (!obj1.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
}
return true;
}
显然,该功能可以进行很多优化,并具有进行深度检查(处理嵌套对象:)的能力,var a = { foo : { fu : "bar" } }
但是您明白了。
正如FOR指出的那样,您可能必须出于自己的目的对此进行调整,例如:不同的类可能具有不同的“等于”定义。如果仅使用普通对象,则上面的内容就足够了,否则,自定义MyClass.equals()
函数可能是解决方法。
为什么要重新发明轮子?给Lodash一试。它具有许多必备功能,例如isEqual()。
_.isEqual(object, other);
就像本页中的其他示例一样,它将使用ECMAScript 5和本机优化(如果浏览器中可用)蛮力检查每个键值。
注:以前这个答案推荐Underscore.js,但lodash做得越来越修复的错误,并与一致性解决问题的一个更好的工作。
当JavaScript for Objects引用内存中的相同位置时,其默认相等运算符将产生true。
var x = {};
var y = {};
var z = x;
x === y; // => false
x === z; // => true
如果您需要其他相等运算符,则需要在类中添加一个equals(other)
方法或类似的方法,而问题域的具体内容将确定这到底意味着什么。
这是一个纸牌示例:
function Card(rank, suit) {
this.rank = rank;
this.suit = suit;
this.equals = function(other) {
return other.rank == this.rank && other.suit == this.suit;
};
}
var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");
queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true
我知道这有点老了,但我想添加一个针对此问题的解决方案。我有一个对象,想知道其数据何时更改。“类似于Object.observe”,我所做的是:
在这里可以复制它,并创建另一组数组以比较值和键。这非常简单,因为它们现在是数组,如果对象的大小不同,则将返回false。