Почему [1,2] + [3,4] = "1,23,4" в JavaScript? - PullRequest
398 голосов
/ 19 августа 2011

Я хотел добавить элементы массива в другой, поэтому я попробовал это:

[1,2] + [3,4]

Он ответил:

"1,23,4"

Что происходит?

Ответы [ 13 ]

506 голосов
/ 19 августа 2011

Оператор + не определен для массивов .

В результате Javascript преобразует массивы в строки и объединяет их.

Обновление

Поскольку этот вопрос и, следовательно, мой ответ получают много внимания, я чувствовал, что было бы полезно и уместно иметь обзор о том, как оператор + ведет себя в целом.

Итак, вот и все.

За исключением E4X и специфических для реализации вещей, Javascript (начиная с ES5) имеет 6 встроенных типов данных :

  1. Не определено
  2. Нулевой
  3. Boolean
  4. номер
  5. Строка
  6. Object

Обратите внимание, что хотя typeof несколько сбивает с толку, возвращает object для Null и function для вызываемых объектов, фактически Null не является объектом, и, строго говоря, в реализациях Javascript, соответствующих спецификации, все функции считается объектами.

Правильно - в 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, Boolean и пользовательских, оператор + не обязательно производит строковый результат. Это может варьироваться в зависимости от реализации преобразования объекта в примитив. Например, var o = { valueOf:function () { return 4; } }; оценка o + 2; производит 6, number, оценка o + '2' производит '42', string.

Чтобы увидеть, как была сгенерирована обзорная таблица, посетите http://jsfiddle.net/1obxuc7m/

243 голосов
/ 19 августа 2011

Оператор 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. Пусть lval будет GetValue(lref).
  3. Пусть rref будет результатом оценки MultiplicativeExpression.
  4. Пусть rval будет GetValue(rref).
  5. Пусть lprim будет ToPrimitive(lval).
  6. Пусть rprim будет ToPrimitive(rval).
  7. Если Type(lprim) равно String или Type(rprim) равно String, то
    1. Возвращает строку, которая является результатом объединения ToString(lprim), за которым следует ToString(rprim)
  8. Вернуть результат применения операции сложения к ToNumber(lprim) и ToNumber(rprim). См. Примечание ниже 11.6.3.

Вы можете видеть, что каждый операнд конвертируется ToPrimitive. Читая далее, мы можем обнаружить, что ToPrimitive всегда будет преобразовывать массивы в строки, что приведет к такому результату.

43 голосов
/ 19 августа 2011

Добавляет два массива , как если бы они были строками .

Строковое представление для первого массива будет "1,2" , а второе будет "3,4" . Поэтому, когда знак + найден, он не может суммировать массивы и затем объединять их как строки.

40 голосов
/ 19 августа 2011

+ объединяет строки, поэтому он преобразует массивы в строки.

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

Чтобы объединить массивы, используйте concat.

[1,2].concat([3,4])
[1,2,3,4]
21 голосов
/ 19 августа 2011

В 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 голосов
/ 19 августа 2011

Это преобразование отдельных массивов в строки, а затем объединение строк.

14 голосов
/ 20 августа 2011

[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);
14 голосов
/ 19 августа 2011

Похоже, JavaScript превращает ваши массивы в строки и соединяет их вместе.Если вы хотите добавить кортежи вместе, вам придется использовать цикл или функцию карты.

12 голосов
/ 19 августа 2011

Он делает именно то, что вы просили.

То, что вы добавляете вместе, это ссылки на массивы (которые JS преобразует в строки), а не числа, как кажется. Это немного похоже на сложение строк: "hello " + "world" = "hello world"

8 голосов
/ 20 августа 2011

было бы неплохо, если бы вы могли перегрузить операторы в JavaScript, но вы не можете: Могу ли я определить пользовательские перегрузки операторов в Javascript? вы можете взломать только оператор "==", который преобразуется в строки перед сравнением: http://blogger.xs4all.nl/peterned/archive/2009/04/01/462517.aspx

...