为什么[1,2]+ [3,4]= 1,23,4"在JavaScript

Why is [1,2] + [3,4] = "1,23,4" in JavaScript?

本文关键字:quot JavaScript 为什么      更新时间:2023-09-26

我想把一个数组中的元素添加到另一个数组中,所以我试着这样做:

[1,2] + [3,4]

它回复:

"1,23,4"

怎么回事?

没有为数组定义+操作符

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

更新

由于这个问题和我的答案得到了很多关注,我觉得有一个概述关于+操作符的一般行为也会很有用和相关。

就这样了。

不包括E4X和特定于实现的东西,Javascript (ES5)有6内置数据类型:

  1. 定义
  2. 零布尔
  3. 字符串

请注意,虽然typeof有些令人困惑地返回object为Null和function为可调用的对象,Null实际上不是一个对象,严格地说,在符合规范的Javascript实现中,所有函数都被认为是对象。

没错——Javascript没有这样的原始数组;只有一个名为Array的对象的实例,加上一些语法糖来减轻痛苦。

更令人困惑的是,包装实体如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;,得到6number, o + '2''42'string

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

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 Section 11.6.1:

11.6.1加法运算符(+)

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

  1. lrefAdditiveExpression的求值结果
  2. lvalGetValue(lref)
  3. rrefMultiplicativeExpression的求值结果
  4. rvalGetValue(rref)
  5. lprimToPrimitive(lval)
  6. rprimToPrimitive(rval)
  7. 如果Type(lprim)StringType(rprim)String,则
    1. 返回ToString(lprim)ToString(rprim)连接的字符串
  8. 返回对ToNumber(lprim)ToNumber(rprim)进行加法运算的结果。

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

将两个数组相加,就好像它们是字符串

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

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

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

要组合数组,使用concat

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

在JavaScript中,二进制加法运算符(+)执行数值加法和字符串连接。然而,当它的第一个参数既不是数字也不是字符串时,它将其转换为字符串(因此是" 1,2 "),然后它对第二个" 3,4 "做同样的处理,并将它们连接到" 1,23,4 "。

尝试使用数组的"concat"方法:

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

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

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

[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);

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

你加在一起的是数组引用(JS转换为字符串),而不是数字,因为它看起来。这有点像把字符串加在一起:"hello " + "world" = "hello world"

如果你能在JavaScript中重载操作符就好了,但你不能:我可以在Javascript中定义自定义操作符重载吗?你只能破解"=="运算符,它会在比较之前转换为字符串:http://blogger.xs4all.nl/peterned/archive/2009/04/01/462517.aspx

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

这里的一些答案解释了意外的不希望的输出('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]

由于ES6,我们可以使用扩展操作符做类似的事情:

[...[1, 2], ...[3, 4]]

给:

[1, 2, 3, 4]

它也适用于命名变量:

const a = [1, 2];
const b = [3, 4];
const array = [...a, ...b];

给出相同的结果。

另一个使用简单"+"号的结果是:

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

所以像这样的东西应该可以工作(但是!):

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

…但是它会将变量a从数组转换为字符串!