Javascript 为什么相等检查不适用于数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30820611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't equality check work with arrays
提问by Hymansonkr
I started with:
我开始于:
"1:2".split(':') == ["1","2"];
// false
Then tried:
然后尝试:
[1,2] == [1,2];
// false
and ultimately:
并最终:
[] == [];
// false
I've since found that:
我后来发现:
"1:2".split(':').toString() == [1,2].toString();
// true
So I've solved my initial issue (kind of) but why can't arrays match each other?
所以我已经解决了我最初的问题(有点)但为什么数组不能相互匹配?
回答by Umberto Raimondi
Javascript arrays are objects and you can't simply use the equality operator ==to understand if the contentof those objects is the same. The equality operator will only test if two object are actually exactly the same instance (e.g. myObjVariable==myObjVariable, works for nulland undefinedtoo).
Javascript 数组是对象,您不能简单地使用相等运算符==来了解这些对象的内容是否相同。相等运算符只会测试两个对象是否实际上是完全相同的实例(例如myObjVariable==myObjVariable,适用于null和undefined)。
If you need to check if two array are equals i'd recommend to just traverse both arrays and verify that all the elements have the same value (and that the two array have the same length).
如果您需要检查两个数组是否相等,我建议只遍历两个数组并验证所有元素是否具有相同的值(并且两个数组具有相同的长度)。
Regarding custom objects equality i'd build instead a specific equalsfunction and i'd add it to the prototype of your class.
关于自定义对象相等性,我会构建一个特定的equals函数,并将其添加到您的类的原型中。
Considering that in the end you converted both arrays to a Stringand tested equality of the resulting strings, you could one day consider using a similar but more generic technique you'll find described in more than a few places:
考虑到最后您将两个数组都转换为 aString并测试了结果字符串的相等性,有一天您可以考虑使用一种类似但更通用的技术,您会在多个地方找到描述:
JSON.stringify(OBJ1) === JSON.stringify(OBJ2)
Well, don't.
好吧,不要。
While this could work if the order of the properties will always the same for those object instances, this leaves the door open for extremely nasty bugs that could be hard to track down. Always favor a more explicit approach and just write a clean and readable function that will test for equality checking all the required fields.
虽然如果这些对象实例的属性顺序始终相同,这可能会起作用,但这为可能难以追踪的极其讨厌的错误敞开了大门。始终支持更明确的方法,只需编写一个干净易读的函数,该函数将测试所有必需字段的相等性。
回答by jfriend00
The ==operator for Objects in Javascript only checks to see if the objects are the same actual object reference, not if they are two separate object that contain the same contents. There is no built in operator for checking if they contain the same contents. You would have to write a function to do that sort of comparison yourself.
==Javascript 中对象的运算符只检查对象是否是相同的实际对象引用,而不是它们是否是包含相同内容的两个单独对象。没有内置运算符来检查它们是否包含相同的内容。您必须编写一个函数来自己进行这种比较。
Your string conversion is one way of comparing two arrays as long as the array elements only contain primitive values (not other objects). If the array elements could contain other elements, then you would have to make sure those objects were themselves converted into representative strings too.
只要数组元素只包含原始值(不包含其他对象),字符串转换就是比较两个数组的一种方法。如果数组元素可以包含其他元素,那么您必须确保这些对象本身也被转换为有代表性的字符串。
And, converting to a string would not discern between an array element that contains "4"versus one that contains 4since both convert to "4"in the string representation.
并且,转换成字符串不会包含数组元素之间辨别"4"与一个包含4由于两个转换到"4"在字符串表示。
回答by Geoffrey Abdallah
Arrays are Objects in JavaScript which are pass by reference. This means that when I initialize an array:
数组是 JavaScript 中通过引用传递的对象。这意味着当我初始化一个数组时:
var array = [1, 2, 3];
I've created a reference to that array in memory. If I then say:
我在内存中创建了对该数组的引用。如果我接着说:
var otherArray = [1, 2, 3];
array and otherArray have two separate addresses in memory so they will not equal eachother (even though the values are equal.) To test out the pass by reference you can play around with arrays by doing:
array 和 otherArray 在内存中有两个单独的地址,因此它们不会彼此相等(即使值相等。)要测试通过引用传递,您可以通过执行以下操作来使用数组:
var copyArray = array;
In this case, copyArray is referencing the same address in memory as array so:
在这种情况下,copyArray 引用与数组相同的内存地址,因此:
copyArray === array; //will evaluate to true
array.push(4); //copyArray will now have values [1, 2, 3, 4];
copyArray.push(5); //array will have values [1, 2, 3, 4, 5];
copyArray === array; //still true
In order to test equality of values in an array or object you need to do a 'deep comparison' - for Arrays this will traverse both arrays to compare index and value to see if both are equal - for objects it will traverse every key and makes sure the value is the same. For more on deep comparisons you can check out the underscore.js annotated source:
为了测试数组或对象中值的相等性,您需要进行“深度比较”-对于数组,这将遍历两个数组以比较索引和值以查看两者是否相等-对于对象,它将遍历每个键并生成确定值是一样的。有关深度比较的更多信息,您可以查看 underscore.js 注释源:
回答by Vinay Aggarwal
In javascript each []is an instance of window.Arrayclass. So you are basically trying to compare two different objects. Since array's can have any no. and any type of elements including Objects and Custom Objects and those nested arrays can again have numerous properties and arrays and so on.
在 javascript 中,每个[]都是window.Array类的一个实例。所以你基本上是在尝试比较两个不同的对象。由于数组可以有任何没有。任何类型的元素,包括对象和自定义对象以及那些嵌套数组,都可以再次拥有众多属性和数组等。
It becomes ambiguous when it comes to comparison, you will never be sure what do you want to do with those objects and nested properties. So what you are trying to achieve by comparing can be done in so many other ways. You just have to figure out the right way for your case.
比较时会变得模棱两可,您永远无法确定要对这些对象和嵌套属性做什么。因此,您尝试通过比较实现的目标可以通过许多其他方式完成。您只需要为您的案例找出正确的方法。
回答by clickbait
One way is to make your own Arraychecking function:
一种方法是制作自己的Array检查功能:
How to compare arrays in JavaScript?!
Another way is to convert the Arrayto a Stringwith .join(), and compare the strings. Then convert them back into Arrays with .split().
另一种方法是将 转换Array为Stringwith .join(),然后比较字符串。然后将它们转换回Arrays .split()。
回答by folkol
Equality for objects will tell you if the two objects are the same one.
对象的相等性将告诉您两个对象是否相同。
var a = [];
var b = a;
a === b; // True, a and b refer to the same object
[] === []; // False, two separate objects
You will have to loop through the arrays to see if they have the same elements.
您必须遍历数组以查看它们是否具有相同的元素。
回答by Ank_247shbm
If I relate this problem with that in Python:
如果我将这个问题与 Python 中的问题联系起来:
Input:
输入:
a="1 2 3 4"
case I:
情况一:
a=input.split(' ')
output: ['1', '2', '3', '4']
输出:['1', '2', '3', '4']
case II:
案例二:
a=map(int,input.split(' '))
output: [1, 2, 3, 4]
输出:[1, 2, 3, 4]
So, the fault is that of type, as it could come-out aa 'true' for:
因此,错误在于类型,因为它可能会出现“真”:
"1:2".split(':').toString() == [1,2].toString(); //true
回答by Dmitry
My guess is that because when javascript was designed, they thought element wise comparison was a rarely used feature so it was never put into the language.
我的猜测是,因为在设计 javascript 时,他们认为元素明智的比较是一个很少使用的功能,因此从未将其放入语言中。
This feature is fairly rare in popular languages; Java doesn't support it, C# doesn't support it, C++ stl types don't support it.
此功能在流行语言中相当罕见;Java 不支持,C# 不支持,C++ stl 类型不支持。
element wise comparison is fairly expensive and complicated compared to reference comparison.
与参考比较相比,元素比较是相当昂贵和复杂的。
In a perfect world, everything can be compared by reference, so that every two objects that have the same state would have the same reference, allowing us to really cheaply check for equality, by just comparing their internal virtual addresses with a simple number comparison.
在一个完美的世界中,一切都可以通过引用进行比较,因此具有相同状态的每两个对象都将具有相同的引用,这使我们能够非常便宜地检查相等性,只需将它们的内部虚拟地址与简单的数字比较进行比较。
Unfortunately, we don't live in a perfect world, and the above is only possible for strings with a string pool, along with few other relatively memory expensive caching options.
不幸的是,我们并不生活在一个完美的世界中,以上仅适用于具有字符串池的字符串,以及其他一些相对内存昂贵的缓存选项。
Some languages like Prolog and Haskell allow comparison by value; eg
Prolog 和 Haskell 等一些语言允许按值进行比较;例如
myProgram :-
Object1 = [1, "something", true, [1,[[], []], true,[false]]],
Object2 = [1, "something", false, [1,[[], []], true,[false]]],
Object3 = [1, "something", true, [1,[[], []], true,[false]]],
Object4 = [1, "something", false, [1,[[], []], true,[false]]],
(Object1 = Object2
-> write("first test passed.")
; write("first test failed\n")),
(Object1 = Object3
-> write("second test passed!\n")
; write("second test failed!\n")),
(Object2 = Object4
-> write("third test passed!\n")
; write("third test failed!")).
You can implement your own deep-comparator in any language by using a map from constructor to a comparator for that constructor. Since JavaScript doesn't have maps from anything but string to object, and javascript clients do not have access to the internal unique identifier of objects, we need to use a table with constructor, comparator pairs, something like below.
通过使用从构造函数到该构造函数的比较器的映射,您可以在任何语言中实现自己的深度比较器。由于 JavaScript 没有从字符串到对象的映射,并且 JavaScript 客户端无法访问对象的内部唯一标识符,因此我们需要使用带有构造函数、比较器对的表,如下所示。
class MyList {
constructor(a, b) {
this.head_ = a;
this.tail_ = b;
}
getHead() {
return this.head_;
}
getTail() {
return this.tail_;
}
setHead(x) {
this.head_ = x;
}
setTail(x) {
this.tail_ = x;
}
equals(other) {
if (typeof other !== 'object') {
console.log(other, 'EEP');
return false;
}
if (!(other instanceof MyList)) {
console.log(other, 'EEP');
return false;
}
var h = this.head_;
var ho = other.getHead();
var cmp1 = comparatorof(h);
if (!cmp1(h, ho)) {
return false;
}
var t = this.tail_;
var to = other.getTail();
var cmp2 = comparatorof(t);
if (!cmp2(t, to)) {
return false;
}
return true;
}
}
var object1 = {
0: "one",
1: "two",
2: ["one", "two", []],
something: {
1: [false, true]
}
};
function strictComparator(a, b) {
return a === b;
}
// given any object, tries finding a function for comparing
// that object to objects of the same kind. Kind being
// used loosely, since some objects like null resist being categorized,
// so these objects need special alteration of the comparatorof itself.
function comparatorof(x) {
if (x === null || x === undefined) {
return strictComparator;
}
x = Object(x); // promote primitives to objects
var ctor = x.constructor;
var c2ct = ctorToComparatorTable;
var n = c2ct.length;
for (var i = 0; i < n; ++i) {
var record = c2ct[i];
var keyCtor = record[0];
if (keyCtor === ctor) {
return record[1];
}
}
throw new TypeError('no comparator exists for ' + x);
}
var ctorToComparatorTable = [
[String, function(a, b) {
return a == b;
}],
[Object, function(a, b) {
for (var key in a) {
var avalue = a[key];
var bvalue = b[key];
var cmp = comparatorof(avalue);
if (!cmp(avalue, bvalue)) {
return false;
}
}
return true;
}],
[Number, function(a, b) {
return a == b;
}],
[Boolean, function(a, b) {
return a == b;
}],
[Array, function(as, bs) {
if (typeof bs !== 'object') {
return false;
}
var nAs = as.length;
var nBs = bs.length;
if (nAs !== nBs) {
return false;
}
for (var i = 0; i < nAs; ++i) {
var a = as[i];
var b = bs[i];
var cmp = comparatorof(a);
if (!cmp(a, b)) {
return false;
}
}
return true;
}],
[MyList, function(a, b) {
return a.equals(b);
}]
];
// true
console.log(comparatorof([])([new MyList(1, new MyList(2, 3))], [new MyList(1, new MyList(2, 3))]));
// true
console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(2, 3))]));
// false
console.log(comparatorof([])([{}, new MyList(1, new MyList(2, 3))], [{}, new MyList(1, new MyList(3, 3))]));
// true
console.log(comparatorof({})({
1: 'one',
one: '1',
x: new MyList(1, {})
}, {
1: 'one',
one: '1',
x: new MyList(1, {})
}));
// true
console.log(comparatorof(2)(
3,
3
));
//true
console.log(comparatorof(true)(
true,
true
));
//false
console.log(comparatorof([])(
[1, 2, new MyList(1, 2)], [1, 2, new MyList(4, 9)]
));
// true
console.log(comparatorof([])(
[1, 2, new MyList(1, 2), null], [1, 2, new MyList(1, 2), null]
));
// false
console.log(comparatorof(null)(
null,
undefined
));
// true
console.log(comparatorof(undefined)(
undefined,
undefined
));
// true
console.log(comparatorof(null)(
null,
null
));
One big issue is that ES6 is already full of features that are incompatible with JScript and Nashorn JJS as well as ActionScript that the language may as well be rebranded as a whole new language every few months, considering that's effectively what you get when you add new features to a language that break compatibility with old versions of it that cannot be replicated without an extra eval layer.
一个大问题是 ES6 已经充满了与 JScript 和 Nashorn JJS 以及 ActionScript 不兼容的特性,考虑到添加新语言时你会得到有效的结果,这种语言可能每隔几个月就被重新命名为一种全新的语言。语言的特性破坏了与旧版本的兼容性,如果没有额外的 eval 层就无法复制。
This problem goes back a long time where on one side you have a minimal language like Lisp which is "easier"(still can't overload ' operator) to introduce "first class" features without breaking backward compatibility, and then you have languages like Perl which cannot be extended with new first-class keywords without an extra eval layer. JavaScript chose the second approach and generally bypasses the consequences by using helper objects like Math, Object to introduce new features, but anytime it wants to add "first class constructs" it ends up breaking backward compatibility.
这个问题可以追溯到很长一段时间,一方面你有一个像 Lisp 这样的最小语言,它“更容易”(仍然不能重载 ' 运算符)来引入“一流”的特性而不破坏向后兼容性,然后你有这样的语言Perl 不能在没有额外 eval 层的情况下使用新的一流关键字进行扩展。JavaScript 选择了第二种方法,并且通常通过使用诸如 Math、Object 之类的辅助对象来引入新功能来绕过后果,但是任何时候它想要添加“第一类构造”,最终都会破坏向后兼容性。
As a proof of concept, In Lisp you can overload == operator, whereas in JavaScript you can't, and in Perl you can but through a mechanism that reserves keywords.
作为概念证明,在 Lisp 中你可以重载 == 运算符,而在 JavaScript 中你不能,而在 Perl 中你只能通过保留关键字的机制。

