为什么在JavaScript中[1,2] + [3,4] =“ 1,23,4”?


405

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

[1,2] + [3,4]

它回应:

"1,23,4"

到底是怎么回事?


1
这是一个与此主题相关的问题:stackoverflow.com/questions/1724255/why-does-2-2-in-javascript
Xavi

29
啊哈哈,虐待狂的面试官甚至可以问类似的东西-这将返回[1,2] + [5,6,7] [1,2]。为什么?
shabunc

9
我认为[1,2] + [3,4]是本周在firebug(在alert('crap')之后)得到最多评价的表达式。
2011年

6
想笑 ?尝试[] + [],{} + [],{} + {}和[] + {}
2012年

1
@shabunc-小心解释原因[5,6,7][1,2]7因为它使用了第二个数组中的最后一个项目。Oo
vsync

Answers:


518

+操作者没有为数组定义

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

 

更新资料

由于这个问题以及我的回答引起了很多关注,因此我认为对操作员的总体行为进行概述也将是有用且相关的+

所以,就到这里。

除E4X和实现特定的内容外,Javascript(自ES5起)具有6种内置数据类型

  1. 未定义
  2. 空值
  3. 布尔型
  4. 宾语

请注意,尽管对于Null和可调用对象而言,typeof 返回值有些混乱 ,但Null实际上不是对象,严格来讲,在符合规范的Javascript实现中,所有函数都被视为对象。objectfunction

没错-Javascript本身没有原始数组;只有Array使用某种语法糖来调用对象的实例才能减轻痛苦。

添加更多的混乱,包装等实体new Number(5)new Boolean(true)并且new String("abc")是所有object类型,而不是数字,布尔值或字符串正如人们所预料。不过对于算术运算符Number,其Boolean行为与数字相同。

容易吧?有了这些,我们就可以继续进行概述了。

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

            || 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所指出的,对于某些对象,例如和和自定义对象Number,操作符不一定会产生字符串结果。它可以根据对象到原始转换的实现而有所不同。例如评估产品a ,评估产品a 。Boolean+var o = { valueOf:function () { return 4; } };o + 2;6numbero + '2''42'string

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


244

JavaScript的+运算符有两个用途:加两个数字或连接两个字符串。它没有针对数组的特定行为,因此它将数组转换为字符串,然后将其连接。

如果你想加入两个数组,以产生一个新的,使用.concat方法代替:

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

如果要高效地将一个数组中的所有元素添加到另一个数组中,则需要使用.push方法

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第11.6.1节中定义:

11.6.1加法运算符(+)

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

  1. 我们lref要评估的结果AdditiveExpression
  2. 我们lvalGetValue(lref)
  3. 我们rref要评估的结果MultiplicativeExpression
  4. 我们rvalGetValue(rref)
  5. 我们lprimToPrimitive(lval)
  6. 我们rprimToPrimitive(rval)
  7. 如果Type(lprim)String或者Type(rprim)String,则
    1. 返回字符串,该字符串是连接ToString(lprim)后跟的结果ToString(rprim)
  8. 返回应用加法运算的结果ToNumber(lprim)ToNumber(rprim)。请参见下面的注释11.6.3。

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


7
+1作为此答案,不仅可以解释问题,而且可以正确地解决问题。
schnaader 2011年

3
这里有一点tmi,但我同意schnaader。最佳答案将解释所要问的问题/错误/行为,然后说明如何产生预期的结果。+1
matthewdunnam 2011年

1
为什么您使用更冗长的Array.prototype.push.apply(data, [3, 4])代替data.concat([3,4])
evilcelery

5
@evilcelery:它们有不同的用途。concat产生一个新的数组,较长的调用有效地扩展了现有的数组。
杰里米·班克斯

1
您可以使用[].push.apply(data, [3,4])较少的冗长性。同样,这可以保证可以抵抗他人更改的值Array
Sam Tobin-Hochstadt 2012年

43

它将两个数组视为字符串相加。

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


是的,这是脑海中第一个独特的解释,但这不是很奇怪的行为吗?也许有一些黑暗的,未知的操作/转换正在完成,我很想知道内部信息:P
okeen 2011年

40

+concats字符串,因此它的数组转换为字符串。

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

要组合数组,请使用concat

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

21

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

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

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

19

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



14

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

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

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

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

12

它正在按照您要求的去做。

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


5
嘿,总是按照我的要求做。问题是要问好问题。令我感兴趣的是添加数组时对数组的toString()解释。
2011年


8

这是因为,+运算符假定操作数不是数字,而是字符串。因此,它首先将它们转换为字符串和concats,以给出最终结果(如果不是数字)。另外,它不支持数组。


2
+运算符不能假定操作数是字符串,因为1 +1 == 2。这是因为未为数组定义“ +”,因此将它们字符串化。
2011年

0

这里的一些答案已经说明了意外的不希望有的输出('1,23,4')的发生方式,还有一些答案已经解释了如何获得假定为期望的所需输出([1,2,3,4])的内容,即数组串联。但是,期望的期望输出的性质实际上有点模棱两可,因为最初的问题只是说明“我想将数组的元素添加到另一个数组中……”。这可能意味着阵列串联,但它可能意味着元组除了(例如这里在这里),即添加元素的标量值在一个阵列中的对应的元件的标量值在第二,例如结合[1,2][3,4]获得[4,6]

假设两个数组的arity / length相同,这是一个简单的解决方案:

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]


-1

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

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

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

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

...但是它将把变量a从数组转换成字符串!记在心上。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.