两个相等数组的比较失败
Comparison of two equal arrays fails
通常,在向 Whosebug 社区发表讲话时,我会尽可能详细地描述我的问题。
但是现在很难说什么。看看下面的图片:
总的来说,colors
在很多方面都改了很多次;而 initial
是常量,用于检查当前状态是否等于初始状态(如果不等于则取消所有更改)。
这个问题看起来很简单,但我坚持了下来。怎么可能,两个相等的数组并不总是相等?
没有带上整个项目的代码,我不知道要添加什么,所以尽管问,我会回答。
JavaScript对象比较(包括数组对象之间的比较)只是比较引用值。两个不同的对象永远不会彼此相等,无论它们看起来如何。
您当然可以根据自己的标准编写自己的数组比较函数,了解一个数组与另一个数组相等的意义。例如,如果数组应包含相同顺序的相同值才被视为相等,则:
function arraysEq(a1, a2) {
if (a1.length != a2.length) return false;
for (var i = 0; i < a1.length; ++i)
if (a1[i] !== a2[i]) return false;
return true;
}
请注意,这只是一个示例;它不应被视为 "how do I compare two arrays" 问题的通用解决方案。
ECMAscript 中的数组也只是对象的一种特殊形式。这反过来意味着,如果您使用 ==
或 ===
将 array1
与 array2
进行比较,您实际上是在比较两个 对象引用 ,不是数组本身,也不是它们的内容。
实际上,如果您可以保证内容始终是字符串,那么您通过 join
对数组进行比较并比较结果的第二种方法也不错。否则,您将不得不循环数组,单独比较每个值,当然还要比较这些数组的 .length
。
Javascript 中的 ==
运算符不比较两个数组或对象的内容。相反,它只是比较两个数组或对象是否实际上是同一个对象。如果你想看看两者是否包含相同的内容,你可以制作自己的比较功能。对于包含字符串的数组,一种可能的方法是使用 .join()
:
colors.join("") === initial.join("")
对于所有可能的数组内容,这并非完全万无一失,但如果您知道数组仅包含字符串并且字符串本身不包含逗号,那么这可以作为一种快捷方式。还可以写一个更健壮的内容对比。对于数组的一级深度比较,您可以使用:
function compareArrays(a, b) {
if (typeof a.length === "number" && a.length === b.length) {
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
return false;
}
对于每个数组都可以包含其他数组或对象的深度比较,您也想比较它们的内容,那么您需要一个可以深度比较对象属性和数组元素的递归解决方案。
您可以像这样对对象和数组进行深入比较:
function compareObjects(a, b) {
// if both are objects, then do a deep comparison of all properties
if (typeof a === "object" && typeof b === "object") {
var aKeys = Object.keys(a).sort(), bKeys = Object.keys(b).sort();
var prop;
if (!compareArrays(aKeys, bKeys)) {
return false;
}
// here we know the two objects have the same keys, check values now
for (var i = 0; i < aKeys.length; i++) {
prop = aKeys[i];
if (typeof a[prop] === "object" && typeof b[prop] === "object") {
if (!compareObjects(a[prop], b[prop])) {
return false;
}
} else if (a[prop] !== b[prop]) {
return false;
}
}
return true;
} else {
// not both objects so just do straight equality
return a === b;
}
}
function compareArrays(a, b) {
if (typeof a.length === "number" && a.length === b.length) {
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
return false;
}
这将允许您比较其中包含对象的嵌套结构,并比较除数组之外的普通对象,如下所示:
var a = {foo: [1,2,3,["a","b","c"]], fee: {a: "1"}};
var b = {fee: {a: "1"}, foo: [1,2,3,4,["a","b","c"]]};
注意:这是比较对象或数组的公开可枚举属性。它不比较自定义形成的对象(比如创建闭包的构造函数)的私有(例如闭包)变量。对于那些,比较它们的唯一方法是使用自定义比较方法,该方法可以访问对象本身的私有数据。
注意:这不适用于包含循环引用的对象或数组(DOM 对象因循环引用而臭名昭著)。可以通过跟踪所有已经在数组或 Set 中进行比较的引用来使其与循环引用一起使用,并且如果已经在比较它们的过程中则不再递归到它们中。
这就是 javascript 等于 (==
) 运算符的工作方式:
这里是严格相等的工作原理 (===
):
在 JavaScript 中我们有 [] === []; // false
因为所有 Objects 都通过引用测试是否相等,你可以在 here (7) and here (1.f).
上查看规范
您可以使用 Array.prototype.every
编写一个函数来执行您想要的测试
function equivArray(a, b) {
return a.length === b.length && a.every(function (e, i) {return e === b[i];});
}
现在
var foo = ['a', 'b', 1, 2],
bar = ['a', 'b', 1, 2];
equivArray(foo, bar); // true
通常,在向 Whosebug 社区发表讲话时,我会尽可能详细地描述我的问题。
但是现在很难说什么。看看下面的图片:
总的来说,colors
在很多方面都改了很多次;而 initial
是常量,用于检查当前状态是否等于初始状态(如果不等于则取消所有更改)。
这个问题看起来很简单,但我坚持了下来。怎么可能,两个相等的数组并不总是相等?
没有带上整个项目的代码,我不知道要添加什么,所以尽管问,我会回答。
JavaScript对象比较(包括数组对象之间的比较)只是比较引用值。两个不同的对象永远不会彼此相等,无论它们看起来如何。
您当然可以根据自己的标准编写自己的数组比较函数,了解一个数组与另一个数组相等的意义。例如,如果数组应包含相同顺序的相同值才被视为相等,则:
function arraysEq(a1, a2) {
if (a1.length != a2.length) return false;
for (var i = 0; i < a1.length; ++i)
if (a1[i] !== a2[i]) return false;
return true;
}
请注意,这只是一个示例;它不应被视为 "how do I compare two arrays" 问题的通用解决方案。
ECMAscript 中的数组也只是对象的一种特殊形式。这反过来意味着,如果您使用 ==
或 ===
将 array1
与 array2
进行比较,您实际上是在比较两个 对象引用 ,不是数组本身,也不是它们的内容。
实际上,如果您可以保证内容始终是字符串,那么您通过 join
对数组进行比较并比较结果的第二种方法也不错。否则,您将不得不循环数组,单独比较每个值,当然还要比较这些数组的 .length
。
Javascript 中的 ==
运算符不比较两个数组或对象的内容。相反,它只是比较两个数组或对象是否实际上是同一个对象。如果你想看看两者是否包含相同的内容,你可以制作自己的比较功能。对于包含字符串的数组,一种可能的方法是使用 .join()
:
colors.join("") === initial.join("")
对于所有可能的数组内容,这并非完全万无一失,但如果您知道数组仅包含字符串并且字符串本身不包含逗号,那么这可以作为一种快捷方式。还可以写一个更健壮的内容对比。对于数组的一级深度比较,您可以使用:
function compareArrays(a, b) {
if (typeof a.length === "number" && a.length === b.length) {
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
return false;
}
对于每个数组都可以包含其他数组或对象的深度比较,您也想比较它们的内容,那么您需要一个可以深度比较对象属性和数组元素的递归解决方案。
您可以像这样对对象和数组进行深入比较:
function compareObjects(a, b) {
// if both are objects, then do a deep comparison of all properties
if (typeof a === "object" && typeof b === "object") {
var aKeys = Object.keys(a).sort(), bKeys = Object.keys(b).sort();
var prop;
if (!compareArrays(aKeys, bKeys)) {
return false;
}
// here we know the two objects have the same keys, check values now
for (var i = 0; i < aKeys.length; i++) {
prop = aKeys[i];
if (typeof a[prop] === "object" && typeof b[prop] === "object") {
if (!compareObjects(a[prop], b[prop])) {
return false;
}
} else if (a[prop] !== b[prop]) {
return false;
}
}
return true;
} else {
// not both objects so just do straight equality
return a === b;
}
}
function compareArrays(a, b) {
if (typeof a.length === "number" && a.length === b.length) {
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
return false;
}
这将允许您比较其中包含对象的嵌套结构,并比较除数组之外的普通对象,如下所示:
var a = {foo: [1,2,3,["a","b","c"]], fee: {a: "1"}};
var b = {fee: {a: "1"}, foo: [1,2,3,4,["a","b","c"]]};
注意:这是比较对象或数组的公开可枚举属性。它不比较自定义形成的对象(比如创建闭包的构造函数)的私有(例如闭包)变量。对于那些,比较它们的唯一方法是使用自定义比较方法,该方法可以访问对象本身的私有数据。
注意:这不适用于包含循环引用的对象或数组(DOM 对象因循环引用而臭名昭著)。可以通过跟踪所有已经在数组或 Set 中进行比较的引用来使其与循环引用一起使用,并且如果已经在比较它们的过程中则不再递归到它们中。
这就是 javascript 等于 (==
) 运算符的工作方式:
这里是严格相等的工作原理 (===
):
在 JavaScript 中我们有 [] === []; // false
因为所有 Objects 都通过引用测试是否相等,你可以在 here (7) and here (1.f).
您可以使用 Array.prototype.every
function equivArray(a, b) {
return a.length === b.length && a.every(function (e, i) {return e === b[i];});
}
现在
var foo = ['a', 'b', 1, 2],
bar = ['a', 'b', 1, 2];
equivArray(foo, bar); // true