为啥 [1,2] + [3,4] = "1,23,4" 在 JavaScript 中?

Posted

技术标签:

【中文标题】为啥 [1,2] + [3,4] = "1,23,4" 在 JavaScript 中?【英文标题】:Why is [1,2] + [3,4] = "1,23,4" in JavaScript?为什么 [1,2] + [3,4] = "1,23,4" 在 JavaScript 中? 【发布时间】:2011-10-30 19:01:56 【问题描述】:

我想将一个数组的元素添加到另一个数组中,所以我尝试了这个:

[1,2] + [3,4]

它的回应是:

"1,23,4"

发生了什么事?

【问题讨论】:

这里有一个与此主题相关的问题:***.com/questions/1724255/why-does-2-2-in-javascript 啊哈哈,虐待狂面试官甚至可以问这样的问题 - 这将返回 [1,2] + [5,6,7][1,2]。为什么? 我认为 [1,2] + [3,4] 是本周 firebug 中评估最多的表达式,仅次于 alert('crap')。 想笑吗?尝试 [] + []、 + []、 + 和 [] + @shabunc - 解释一下为什么[5,6,7][1,2]7,因为它使用了第二个数组中的最后一项。 O.o 【参考方案1】:

这里的一些答案已经解释了意外的不想要的输出 ('1,23,4') 是如何发生的,有些答案已经解释了如何获得他们认为是预期的期望输出 ([1,2,3,4]),即数组连接。然而,预期的期望输出的性质实际上有点模棱两可,因为最初的问题只是简单地说“我想将一个数组的元素添加到另一个......”。 可以表示数组连接,但表示元组加法(例如here和here),即将一个数组中元素的标量值添加到标量第二个中相应元素的值,例如结合[1,2][3,4]得到[4,6]

假设两个数组具有相同的数量/长度,这是一个简单的解决方案:

const arr1 = [1, 2];
const arr2 = [3, 4];

const add = (a1, a2) => a1.map((e, i) => e + a2[i]);

console.log(add(arr1, arr2)); // ==> [4, 6]

【讨论】:

【参考方案2】:

JavaScript 的+ 运算符有两个用途:添加两个数字,或连接两个字符串。它对数组没有特定的行为,所以它将它们转换为字符串然后加入它们。

如果您想连接两个数组以生成一个新数组,请改用the .concat method:

[1, 2].concat([3, 4]) // [1, 2, 3, 4]

如果你想高效地将一个数组中的所有元素添加到另一个数组中,你需要使用the .push method:

var data = [1, 2];

// ES6+:
data.push(...[3, 4]);
// or legacy:
Array.prototype.push.apply(data, [3, 4]);

// data is now [1, 2, 3, 4]

+ 运算符的行为在ECMA-262 5e Section 11.6.1 中定义:

11.6.1 加法运算符 (+)

加法运算符执行字符串连接或数字加法。产生式AdditiveExpression : AdditiveExpression + MultiplicativeExpression 评估如下:

    lref 成为评估AdditiveExpression 的结果。 让lval 成为GetValue(lref)。 让rref 成为评估MultiplicativeExpression 的结果。 让rval 成为GetValue(rref)。 让lprim 成为ToPrimitive(lval)。 让rprim 成为ToPrimitive(rval)。 如果Type(lprim)StringType(rprim)String,那么
      返回字符串,它是连接ToString(lprim) 后跟ToString(rprim) 的结果
    将加法运算的结果返回到ToNumber(lprim)ToNumber(rprim)。请参阅下面 11.6.3 的注释。

您可以看到每个操作数都转换为ToPrimitive。通过进一步阅读我们可以发现ToPrimitive 总是会将数组转换为字符串,从而产生这个结果。

【讨论】:

+1 因为这个答案不仅解释了问题,还解释了如何正确地做。 这里有一点tmi,但我同意schnaader。最佳答案解释了所询问的问题/错误/行为,然后显示了如何产生预期的结果。 +1 为什么要使用更详细的Array.prototype.push.apply(data, [3, 4]) 而不是data.concat([3,4]) @evilcelery:它们有不同的用途。 concat 产生一个 new 数组,更长的调用有效地扩展了一个 existing 数组。 您可以使用[].push.apply(data, [3,4]) 来减少冗长。此外,这可以保证防止其他人更改 Array 的值。【参考方案3】:

+ 运算符没有为数组定义

发生的是 Javascript 将数组转换为字符串并将它们连接起来。

 

更新

由于这个问题以及因此我的回答引起了很多关注,我觉得对+ 运算符的一般行为方式进行概述会很有用且相关。

所以,就这样吧。

不包括 E4X 和特定于实现的东西,Javascript(从 ES5 开始)有 6 内置 data types:

    未定义 空 布尔值 号码 字符串 对象

请注意,尽管typeof somewhat confusingly returns object 用于 Null,function 用于可调用对象,但 Null 实际上不是对象,严格来说,在符合规范的 Javascript 实现中,所有函数都被视为对象。

没错 - Javascript 本身就没有原始数组;只有一个名为 Array 的 Object 实例,并带有一些语法糖以减轻痛苦。

更令人困惑的是,new Number(5)new Boolean(true)new String("abc") 等包装实体都是 object 类型,而不是人们可能期望的数字、布尔值或字符串。尽管如此,对于算术运算符 NumberBoolean 的行为就像数字一样。

简单吧?完成所有这些之后,我们可以继续进行概述。

+ 的不同结果类型(按操作数类型)

            || undefined | null   | boolean | number | string | object |
=========================================================================
 undefined  || number    | number | number  | number | string | string | 
 null       || number    | number | number  | number | string | string | 
 boolean    || number    | number | number  | number | string | string | 
 number     || number    | number | number  | number | string | string | 
 string     || string    | string | string  | string | string | string | 
 object     || string    | string | string  | string | string | string | 

* 适用于 Chrome13、FF6、Opera11 和 IE9。检查其他浏览器和版本留给读者作为练习。

注意: 正如CMS 所指出的,对于NumberBoolean 和自定义对象等特定情况,+ 运算符不一定会产生字符串结果.它可以根据对象到原始转换的实现而有所不同。例如var o = valueOf:function () return 4; ; 评估o + 2; 产生6,一个number,评估o + '2' 产生'42',一个string

要查看概览表是如何生成的,请访问http://jsfiddle.net/1obxuc7m/

【讨论】:

【参考方案4】:

仅使用简单的“+”号的另一个结果是:

[1,2]+','+[3,4] === [1,2,3,4]

所以这样的事情应该可以工作(但是!):

var a=[1,2];
var b=[3,4];
a=a+','+b; // [1,2,3,4]

... 但它会将变量 a 从数组转换为字符串!记住这一点。

【讨论】:

【参考方案5】:

这是因为,+ 运算符假定操作数是字符串,如果它们不是数字的话。因此,如果它不是数字,它首先将它们转换为字符串并连接以给出最终结果。另外,它不支持数组。

【讨论】:

+ 运算符不能假定操作数是字符串,因为 1 + 1 == 2 等等。这是因为没有为数组定义'+',所以它对它们进行String-s。【参考方案6】:

JavaScript 中的[1,2]+[3,4] 与评估相同:

new Array( [1,2] ).toString() + new Array( [3,4] ).toString();

所以要解决您的问题,最好的办法是就地添加两个数组或不创建新数组:

var a=[1,2];
var b=[3,4];
a.push.apply(a, b);

【讨论】:

【参考方案7】:

如果您可以在 JavaScript 中重载运算符但您不能: Can I define custom operator overloads in Javascript? 您只能破解在比较之前转换为字符串的“==”运算符: http://blogger.xs4all.nl/peterned/archive/2009/04/01/462517.aspx

【讨论】:

【参考方案8】:

它将两个数组添加为字符串

第一个数组的字符串表示为 "1,2",第二个数组表示为 "3,4"。因此,当找到+ 符号时,它不能对数组求和然后将它们连接为字符串。

【讨论】:

是的,这是脑海中第一个独特的解释,但是,这不是很奇怪的行为吗?也许正在进行一些黑暗的、未知的操作/改造,我很想知道内部情况:P【参考方案9】:

在 JavaScript 中,二进制加法运算符 (+) 执行数字加法和字符串连接。但是,当它的第一个参数既不是数字也不是字符串时,它会将其转换为字符串(因此为“1,2”),然后它对第二个“3,4”执行相同操作并将它们连接到“1,23,4” .

尝试使用数组的“concat”方法:

var a = [1, 2];
var b = [3, 4];
a.concat(b) ; // => [1, 2, 3, 4];

【讨论】:

【参考方案10】:

+ 连接字符串,因此它将数组转换为字符串。

[1,2] + [3,4]
'1,2' + '3,4'
1,23,4

要组合数组,请使用concat

[1,2].concat([3,4])
[1,2,3,4]

【讨论】:

【参考方案11】:

它将单个数组转换为字符串,然后组合字符串。

【讨论】:

【参考方案12】:

看起来 JavaScript 正在将您的数组转换为字符串并将它们连接在一起。如果要将元组添加在一起,则必须使用循环或映射函数。

【讨论】:

【参考方案13】:

它正在做你要求它做的事情。

您要添加的是数组引用(JS 将其转换为字符串),而不是看起来的数字。这有点像将字符串加在一起:"hello " + "world" = "hello world"

【讨论】:

呵呵,它总是按我的要求做。问题是提出好的问题。让我感兴趣的是添加数组时对数组的 toString() 解释。

以上是关于为啥 [1,2] + [3,4] = "1,23,4" 在 JavaScript 中?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 1+ +"2"+3 在 JavaScript 中计算为 6? [复制]

python 的range()函数怎么使用,为啥单独运行print(range(1,5))输出还是range(1,5),而不是[1,2,3,4]

Java中的Set类差集问题?差集为啥是1,2不是1,2,8,9,;

为啥“x”的值发生了变化? [复制]

为啥JavaFX Scene Builder打开失败,版本1.1和2.0都一样

关于PHP中array_rand函数为啥不能只设置一个随机?