Por que [1,2] + [3,4] = "1,23,4" em JavaScript?

405

Eu queria adicionar os elementos de uma matriz em outra, então tentei o seguinte:

[1,2] + [3,4]

Respondeu com:

"1,23,4"

O que está acontecendo?

okeen
fonte
1
Aqui está uma pergunta relacionada a este tópico: stackoverflow.com/questions/1724255/why-does-2-2-in-javascript
Xavi
29
Ah-ha-ha, o entrevistador sádico pode perguntar até algo como - como isso retornará [1,2] + [5,6,7] [1,2]. porque?
precisa saber é o seguinte
9
Eu acho que [1,2] + [3,4] foi a expressão mais avaliada no firebug esta semana, após alerta ('porcaria').
Okeen
6
Quer rir ? Tente [] + [], {} + [], {} + {} e [] + {}
Intrepidd
1
@shabunc - o cuidado de explicar por que [5,6,7][1,2]é 7porque ele usa o último item na segunda matriz. Oo
vsync

Respostas:

518

O +operador não está definido para matrizes .

O que acontece é que o Javascript converte matrizes em seqüências de caracteres e concatena essas.

 

Atualizar

Como essa pergunta e, consequentemente, minha resposta está recebendo muita atenção, senti que seria útil e relevante ter uma visão geral sobre como o +operador também se comporta em geral.

Então, aqui vai.

Excluindo E4X e outras coisas específicas de implementação, Javascript (a partir de ES5) tem 6 built-in tipos de dados :

  1. Indefinido
  2. Nulo
  3. boleano
  4. Número
  5. Corda
  6. Objeto

Observe que, embora typeof um pouco confuso retorne object para Null e functionpara objetos que podem ser chamados, Null na verdade não é um Object e, estritamente falando, nas implementações Javascript em conformidade com as especificações, todas as funções são consideradas objetos.

Isso mesmo - o Javascript não possui matrizes primitivas ; apenas instâncias de um objeto chamado Arraycom um pouco de açúcar sintático para aliviar a dor.

Adicionando mais à confusão, as entidades do invólucro, como new Number(5), new Boolean(true)e new String("abc")são do objecttipo, não são números, booleanos ou seqüências de caracteres, como seria de esperar. No entanto, para operadores aritméticos Numbere Booleanse comportam como números.

Calma, né? Com tudo isso fora do caminho, podemos avançar para a própria visão geral.

Diferentes tipos de resultado por tipos de +operando

            || 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 | 

* aplica-se ao Chrome13, FF6, Opera11 e IE9. A verificação de outros navegadores e versões é deixada como um exercício para o leitor.

Nota: Como apontado por CMS , em determinados casos de objectos, tais como Number, Booleane os personalizados do +operador não necessariamente produzir um resultado string. Pode variar dependendo da implementação do objeto em conversão primitiva. Por exemplo, var o = { valueOf:function () { return 4; } };avaliar o + 2;produz 6, a number, avaliar o + '2'produz '42', a string.

Para ver como a tabela de visão geral foi gerada, visite http://jsfiddle.net/1obxuc7m/

Saul
fonte
244

O +operador do JavaScript tem dois propósitos: adicionar dois números ou unir duas strings. Ele não possui um comportamento específico para matrizes, portanto, é convertê-las em strings e depois juntá-las.

Se você deseja unir duas matrizes para produzir uma nova, use o .concatmétodo :

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

Se você deseja adicionar com eficiência todos os elementos de uma matriz para outra, é necessário usar o método .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]

O comportamento do +operador é definido na Seção 11.6.1 do ECMA-262 5e :

11.6.1 O operador Adição (+)

O operador de adição executa concatenação de sequência ou adição numérica. A produção AdditiveExpression : AdditiveExpression + MultiplicativeExpressioné avaliada da seguinte forma:

  1. Seja lrefo resultado da avaliação AdditiveExpression.
  2. Let lvalbe GetValue(lref).
  3. Seja rrefo resultado da avaliação MultiplicativeExpression.
  4. Let rvalbe GetValue(rref).
  5. Let lprimbe ToPrimitive(lval).
  6. Let rprimbe ToPrimitive(rval).
  7. Se Type(lprim)é Stringou Type(rprim)é String, então
    1. Retorne a String resultante da concatenação ToString(lprim)seguida porToString(rprim)
  8. Retorne o resultado da aplicação da operação de adição a ToNumber(lprim)e ToNumber(rprim). Veja a nota abaixo 11.6.3.

Você pode ver que cada operando é convertido ToPrimitive. Lendo mais adiante, podemos descobrir que ToPrimitivesempre converterá matrizes em strings, produzindo esse resultado.

Jeremy Banks
fonte
7
+1, pois essa resposta não apenas explica o problema, mas também explica como fazê-lo corretamente.
#
3
há um pouco de tmi aqui, mas eu concordo com o schnaader. As melhores respostas explicam o problema / erro / comportamento que está sendo perguntado e mostram como produzir o resultado pretendido. 1
matthewdunnam
1
Por que você usaria os mais detalhados em Array.prototype.push.apply(data, [3, 4])vez de data.concat([3,4])?
Evilcelery
5
@evilcelery: Eles servem a propósitos diferentes. concatproduz uma nova matriz, a chamada mais longa estende com eficiência uma matriz existente .
Jeremy Banks
1
Você pode usar [].push.apply(data, [3,4])para um pouco menos de verbosidade. Além disso, isso garante resistência a outras pessoas que alteram o valor de Array.
Sam Tobin-Hochstadt 11/01
43

Ele adiciona as duas matrizes como se fossem strings .

A representação de string para a primeira matriz seria "1,2" e a segunda seria "3,4" . Portanto, quando o +sinal é encontrado, ele não pode somar matrizes e concatená-las como strings.

Doug
fonte
Sim, essa é a primeira e única explicação que vem à mente, mas esse não é um comportamento muito estranho? talvez haja alguma escuro, operação unknow / transformação que está sendo feito, e eu gostaria de saber as ampolas: P
Okeen
40

O +concats strings, portanto, converte as matrizes em strings.

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

Para combinar matrizes, use concat.

[1,2].concat([3,4])
[1,2,3,4]
Foguete Hazmat
fonte
21

Em JavaScript, o operador de adição binária ( +) executa adição numérica e concatenação de cadeias. No entanto, quando o primeiro argumento não é um número nem uma string, ele é convertido em uma string (portanto, " 1,2"), então ele faz o mesmo com o segundo " 3,4" e os concatena em " 1,23,4".

Tente usar o método "concat" de matrizes:

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

Ele está convertendo as matrizes individuais em seqüências de caracteres e, em seguida, combinando-as.

tadman
fonte
14

Parece que o JavaScript está transformando suas matrizes em strings e juntando-as. Se você deseja adicionar tuplas, precisará usar um loop ou uma função de mapa.

Adam Fabicki
fonte
14

[1,2]+[3,4] em JavaScript é o mesmo que avaliar:

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

e, para resolver seu problema, o melhor seria adicionar duas matrizes no local ou sem criar uma nova matriz:

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

Está fazendo exatamente o que você pediu.

O que você está adicionando são referências de matriz (que JS converte em strings), não números como parece. É como adicionar cordas: "hello " + "world"="hello world"

Jamie Dixon
fonte
5
hehe, SEMPRE faz o que eu pedi. O problema é fazer a boa pergunta. O que me intriga é a interpretação toString () das matrizes quando você as adiciona.
okeen 19/08/11
8

Isso ocorre porque, operador + assume que os operandos são string, se não forem números. Portanto, primeiro os converte em string e concats para fornecer o resultado final, se não for um número. Além disso, ele não suporta matrizes.

Prashant Singh
fonte
2
O operador + NÃO pode assumir que os operandos são seqüências de caracteres, porque 1 + 1 == 2, entre outros. É porque '+' não está definido para matrizes e, portanto, é usado para strings.
Okeen
0

Algumas respostas aqui explicaram como a saída indesejada inesperada ( '1,23,4') acontece e algumas explicaram como obter o que elas assumem ser a saída desejada desejada ( [1,2,3,4]), ou seja, concatenação de matriz. No entanto, a natureza do resultado esperado esperado é realmente um tanto ambígua, porque a pergunta original simplesmente declara "eu queria adicionar os elementos de uma matriz em outra ...". Isso pode significar concatenação de matriz, mas também adição de tupla (por exemplo, aqui e aqui ), ou seja, adicionar os valores escalares de elementos em uma matriz aos valores escalares dos elementos correspondentes na segunda, por exemplo, combinar [1,2]e [3,4]obter [4,6].

Supondo que ambas as matrizes tenham a mesma área / comprimento, aqui está uma solução simples:

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]

Andrew Willems
fonte
-1

Outro resultado usando apenas um sinal "+" simples será:

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

Então, algo assim deve funcionar (mas!):

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

... mas converterá a variável a de uma matriz para String! Tenha isso em mente.

Cravo
fonte