为什么JavaScript中的 + =“1,23,4”?

我想添加一个数组的元素到另一个,所以我试过这个:

[1,2] + [3,4] 

它的回应是:

 "1,23,4" 

到底是怎么回事?

+运算符没有为数组定义

会发生什么是Javascript 将数组转换为string并将其连接起来。

更新

由于这个问题,因此我的答案得到了很多的关注,我觉得这将是有用的和相关的概述 +操作符如何performance一般也。

所以,在这里呢。

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

  1. 未定义
  2. 空值
  3. 布尔
  4. 目的

请注意,尽pipetypeof 有点混淆地返回 Null object和可调用对象的function ,但Null实际上不是Object,严格来说,在符合规范的Javascript实现中,所有函数都被视为Object。

没错 – Javascript 没有原始数组 , 只有一个名为Array的对象的实例带有一些语法糖来缓解疼痛。

添加更多的困惑,像new Number(5)new Boolean(true)new String("abc")包装实体都是objecttypes,而不是数字,布尔值或string,如人们所期望的。 尽pipe如此,算术运算符NumberBoolean行为与数字相同。

很简单,嗯? 所有这一切,我们可以转到概述本身。

+按操作数types的不同结果types

  || 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和Custom等对象的某些情况, +运算符不一定会产生string结果。 它可以根据对象到原始转换的实现而变化。 例如var o = { valueOf:function () { return 4; } }; var o = { valueOf:function () { return 4; } }; 评估o + 2; 产生6 ,一个number ,评估o + '2'产生'42' ,一个string

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

JavaScript的+运算符有两个目的:添加两个数字,或者连接两个string。 它没有数组的特定行为,所以它将它们转换为string,然后join它们。

如果您想要连接两个数组来产生一个新数组,请使用.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加法运算符(+)

加法运算符可以执行string连接或数字加法。 生产AdditiveExpression : AdditiveExpression + MultiplicativeExpression的计算方法如下:

  1. lref是评估AdditiveExpression的结果。
  2. lval成为GetValue(lref)
  3. rref是评估MultiplicativeExpression的结果。
  4. rvalGetValue(rref)
  5. lprim成为ToPrimitive(lval)
  6. rprim成为ToPrimitive(rval)
  7. 如果Type(lprim)StringType(rprim)String ,那么
    1. 返回连接ToString(lprim)ToString(rprim)的string,
  8. 将加法操作的结果返回给ToNumber(lprim)ToNumber(rprim) 。 见下面的注释11.6.3。

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

它添加了两个数组 ,就好像它们是string一样

第一个数组的string表示将是“1,2” ,第二个将是“3,4” 。 所以当find+符号时,它不能对数组进行求和,然后将它们连接成string。

+连接string,所以它将数组转换为string。

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

要组合数组,请使用concat

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

在JavaScript中,二进制加法运算符( + )执行数字加法和string连接。 然而,当它的第一个参数既不是一个数字也不是一个string,那么它将它转换成一个string(因此“ 1,2 ”),然后它与第二个“ 3,4 ”相同,并将它们连接到“ 1,23,4 “。

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

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

它将单个数组转换为string,然后组合string。

它看起来像JavaScript是把你的数组变成string,并将它们连接在一起。 如果你想一起添加元组,你将不得不使用循环或者map函数。

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

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

所以要解决你的问题,最好的办法是在原地添加两个数组,或者不创build一个新的数组:

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

这正是你要求的。

你一起join的是数组引用(将JS转换为string),而不是数字。 这有点像添加string: "hello " + "world" = "hello world"

如果你可以在JavaScript中重载操作符,但你不能: 我可以在JavaScript中定义自定义操作符重载吗? 您只能在比较之前破解转换为string的“==”运算符: http : //blogger.xs4all.nl/peterned/archive/2009/04/01/462517.aspx

这是因为,+运算符假定操作数是string,如果它们不是数字。 所以,它首先将它们转换为string和连字符以给出最终结果,如果它不是一个数字。 另外,它不支持数组。

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

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

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

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

…但它会将variablesa从一个数组转换为string! 记在心上。

这里的一些答案已经解释了意外的不期望的输出( '1,23,4' )是怎么发生的,有些解释了如何获得它们所期望的期望输出( [1,2,3,4] ),即数组级联。 然而,期望的期望输出的性质实际上有些模棱两可,因为原来的问题只是简单地陈述了“我想将一个数组的元素添加到另一个…”中。 这可能意味着数组连接,但也可能意味着元组添加(例如这里和这里 ),即将一个数组中元素的标量值与第二个元素中的相应元素的标量值相加,例如[1,2][3,4]来获得[4,6]

假设两个arrays具有相同的长度/长度,下面是一个简单的解决scheme:

 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]