我开始时:
"1:2".split(':') == ["1","2"];
// false
然后尝试了:
[1,2] == [1,2];
// false
最终:
[] == [];
// false
我发现了:
"1:2".split(':').toString() == [1,2].toString();
// true
所以我已经解决了我的初始问题(种类),但为什么数组不能相互匹配?
答案 0 :(得分:31)
Javascript数组是对象,您不能简单地使用等于运算符footer-div
来理解这些对象的内容是否相同。等于运算符仅测试两个对象实际上是否完全相同(例如==
,适用于myObjVariable==myObjVariable
和null
)。
如果你需要检查两个数组是否相等,我建议只遍历两个数组并验证所有元素是否具有相同的值(并且两个数组的长度相同)。
关于自定义对象的相同性,我构建了一个特定的undefined
函数,并将其添加到您的类的原型中。
考虑到最后你将两个数组转换为equals
并测试了结果字符串的相等性,你可能有一天会考虑使用一种类似但更通用的技术,你会发现它不仅仅是几个地方:
String
嗯,不。
虽然如果属性的顺序对于那些对象实例总是相同的,这可能会起作用,但是这样就可以打开那些难以追踪的非常讨厌的错误。总是喜欢更明确的方法,只需编写一个干净且可读的函数来测试相等性检查所有必需的字段。
答案 1 :(得分:10)
Javascript中的Objects的==
运算符仅检查对象是否是相同的实际对象引用,而不是它们是包含相同内容的两个单独对象。没有内置运算符来检查它们是否包含相同的内容。您必须自己编写一个函数来进行这种比较。
只要数组元素只包含原始值(而不是其他对象),您的字符串转换就是比较两个数组的一种方法。如果数组元素可以包含其他元素,那么您必须确保这些对象本身也被转换为代表性字符串。
并且,转换为字符串不会在包含"4"
的数组元素与包含4
的数组元素之间辨别,因为它们都会在字符串表示形式中转换为"4"
。
答案 2 :(得分:6)
数组是JavaScript中的对象,通过引用传递。这意味着当我初始化一个数组时:
var array = [1, 2, 3];
我在内存中创建了对该数组的引用。如果我然后说:
var otherArray = [1 2, 3];
array和otherArray在内存中有两个独立的地址,因此它们不会相互相等(即使值相等。)要测试通过引用传递,您可以通过执行以下操作来使用数组:
var copyArray = array;
在这种情况下,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
为了测试数组或对象中值的相等性,你需要进行“深度比较” - 对于数组,这将遍历两个数组以比较索引和值以查看两者是否相等 - 对于它将遍历每个对象的对象键并确保值相同。有关深度比较的更多信息,请查看underscore.js带注释的源:
答案 3 :(得分:2)
在javascript中,每个[]
都是window.Array
类的实例。所以你基本上是想比较两个不同的对象。因为数组可以没有任何数据。任何类型的元素,包括对象和自定义对象,那些嵌套的数组可以再次拥有许多属性和数组,等等。
在比较时变得模棱两可,你永远不会确定你想用这些对象和嵌套属性做什么。因此,您通过比较尝试实现的目标可以通过许多其他方式完成。你必须找到适合你案件的正确方法。
答案 4 :(得分:1)
一种方法是制作自己的Array
检查功能:
How to compare arrays in JavaScript?!
另一种方法是使用Array
将String
转换为.join()
,并比较字符串。然后使用Array
将它们转换回.split()
。
答案 5 :(得分:0)
对象的平等性将告诉您这两个对象是否是同一个。
var a = [];
var b = a;
a === b; // True, a and b refer to the same object
[] === []; // False, two separate objects
您必须遍历数组以查看它们是否具有相同的元素。
答案 6 :(得分:0)
如果我将此问题与Python相关联:
输入:
a="1 2 3 4"
案例I:
a=input.split(' ')
输出:['1','2','3','4']
情况二:
a=map(int,input.split(' '))
输出:[1、2、3、4]
所以,错误是类型的错误,因为它可能对以下情况显示为“ true”:
"1:2".split(':').toString() == [1,2].toString(); //true
答案 7 :(得分:-1)
我的猜测是因为当设计javascript时,他们认为元素明智的比较是一个很少使用的功能,因此它从未被放入语言中。
此功能在流行语言中相当罕见; Java不支持它,C#不支持它,C ++ stl类型不支持它。
与参考比较相比,元素智能比较相当昂贵且复杂。在一个完美的世界中,所有东西都可以通过引用进行比较,这样每个具有相同状态的两个对象都会有相同的引用,只需将它们的内部虚拟地址与简单的内容进行比较,就可以非常便宜地检查相等性数字比较。
不幸的是,我们并没有生活在一个完美的世界中,上述内容只适用于带字符串池的字符串,以及其他一些相对内存昂贵的缓存选项。
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!")).
您可以使用从构造函数到该构造函数的比较器的映射,以任何语言实现您自己的深度比较器。由于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
));
一个很大的问题是,ES6已经充满了与JScript和Nashorn JJS以及ActionScript不兼容的功能,这种语言可能每隔几个月就会被重新命名为一种全新的语言,考虑到这是有效的。您将新功能添加到一种语言中,该语言会破坏与旧版本的兼容性,如果没有额外的评估图层则无法复制。
这个问题可以追溯到很长一段时间,你有一个像Lisp这样的最小语言,它“更容易”(仍然不能超载'运算符)引入“一流”功能而不破坏向后兼容性,然后你拥有像Perl这样的语言,如果没有额外的eval层,就无法使用新的一流关键字进行扩展。 JavaScript选择了第二种方法,并且通常通过使用Math,Object等辅助对象来引入新功能来绕过后果,但是只要它想要添加“第一类构造”,它最终会破坏向后兼容性。
作为一个概念证明,在In Lisp中你可以重载==运算符,而在JavaScript中你不能,而在Perl中你可以通过一种保留关键字的机制。