¿Por qué es [1,2] + [3,4] = "1,23,4" en JavaScript?

405

Quería agregar los elementos de una matriz a otra, así que intenté esto:

[1,2] + [3,4]

Respondió con:

"1,23,4"

Que esta pasando?

okeen
fuente
1
Aquí hay una pregunta relacionada con este tema: stackoverflow.com/questions/1724255/why-does-2-2-in-javascript
Xavi
29
Ah-ha-ha, el entrevistador sádico puede preguntar incluso algo como: ¿qué devolverá esto [1,2] + [5,6,7] [1,2]. ¿por qué?
shabunc
99
Creo que [1,2] + [3,4] ha sido la expresión más evaluada en firebug esta semana, después de la alerta ('basura').
Okeen
66
Quiero reir ? Pruebe [] + [], {} + [], {} + {} y [] + {}
Intrepidd el
1
@shabunc: cuidado de explicar por qué [5,6,7][1,2]es 7porque usa el último elemento de la segunda matriz. Oo
vsync

Respuestas:

518

El +operador no está definido para matrices .

Lo que sucede es que Javascript convierte las matrices en cadenas y las concatena.

 

Actualizar

Desde esta pregunta y, en consecuencia, mi respuesta está recibiendo mucha atención, sentí que sería útil y relevante tener una visión general sobre cómo se +comporta el operador en general también.

Entonces, aquí va.

Excluyendo E4X y cosas específicas de implementación, Javascript (a partir de ES5) tiene 6 tipos de datos integrados :

  1. Indefinido
  2. Nulo
  3. Booleano
  4. Número
  5. Cuerda
  6. Objeto

Tenga en cuenta que, aunque resulta un typeof tanto confuso object para Null y functionpara Objetos invocables, Null en realidad no es un Objeto y, estrictamente hablando, en las implementaciones de JavaScript que cumplen con las especificaciones, todas las funciones se consideran Objetos.

Así es: Javascript no tiene matrices primitivas como tales; solo casos de un Objeto llamado Arraycon un poco de azúcar sintáctica para aliviar el dolor.

Agregando más a la confusión, las entidades de contenedor como new Number(5), new Boolean(true)y new String("abc")son todas de objecttipo, no números, booleanos o cadenas como cabría esperar. Sin embargo para operadores aritméticos Numbery se Booleancomportan como números.

Fácil, ¿eh? Con todo eso fuera del camino, podemos pasar a la visión general en sí.

Diferentes tipos de resultados por tipo 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 | 

* se aplica a Chrome13, FF6, Opera11 e IE9. La comprobación de otros navegadores y versiones se deja como ejercicio para el lector.

Nota: Como se ha señalado por la CMS , para ciertos casos de objetos tales como Number, Booleany los personalizados del +operador no necesariamente producir un resultado cadena. Puede variar según la implementación del objeto a la conversión primitiva. Por ejemplo, var o = { valueOf:function () { return 4; } };evaluar o + 2;produce 6, a number, evaluar o + '2'produce '42', a string.

Para ver cómo se generó la tabla de resumen, visite http://jsfiddle.net/1obxuc7m/

Saulo
fuente
244

El +operador de JavaScript tiene dos propósitos: agregar dos números o unir dos cadenas. No tiene un comportamiento específico para las matrices, por lo que las convierte en cadenas y luego las une.

Si desea unir dos matrices para producir una nueva, utilice el .concatmétodo en su lugar:

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

Si desea agregar eficientemente todos los elementos de una matriz a otra, debe usar el 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]

El comportamiento del +operador se define en ECMA-262 5e Sección 11.6.1 :

11.6.1 El operador de adición (+)

El operador de suma realiza la concatenación de cadenas o la suma numérica. La producción AdditiveExpression : AdditiveExpression + MultiplicativeExpressionse evalúa de la siguiente manera:

  1. Dejar lrefser el resultado de evaluar AdditiveExpression.
  2. Dejar que lvalsea GetValue(lref).
  3. Dejar rrefser el resultado de evaluar MultiplicativeExpression.
  4. Dejar que rvalsea GetValue(rref).
  5. Dejar que lprimsea ToPrimitive(lval).
  6. Dejar que rprimsea ToPrimitive(rval).
  7. Si Type(lprim)es Stringo Type(rprim)es String, entonces
    1. Devuelve la cadena que es el resultado de la concatenación ToString(lprim)seguida deToString(rprim)
  8. Devuelve el resultado de aplicar la operación de suma a ToNumber(lprim)y ToNumber(rprim). Ver la Nota a continuación 11.6.3.

Puede ver que cada operando se convierte ToPrimitive. Al leer más, podemos encontrar que ToPrimitivesiempre convertirá matrices en cadenas, produciendo este resultado.

Jeremy Banks
fuente
77
+1 ya que esta respuesta no solo explica el problema, sino que también explica cómo hacerlo correctamente.
schnaader
3
Hay un poco de TMI aquí, pero estoy de acuerdo con Schnaader. Las mejores respuestas explican el problema / error / comportamiento sobre el que se pregunta y luego muestra cómo producir el resultado deseado. +1
matthewdunnam
1
¿Por qué usarías el más detallado en Array.prototype.push.apply(data, [3, 4])lugar de data.concat([3,4])?
evilcelery
55
@evilcelery: Sirven para diferentes propósitos. concatproduce una nueva matriz, la llamada más larga extiende eficientemente una matriz existente .
Jeremy Banks
1
Puede usar [].push.apply(data, [3,4])para un poco menos de verbosidad. Además, se garantiza que será resistente a que otras personas cambien el valor de Array.
Sam Tobin-Hochstadt
43

Agrega las dos matrices como si fueran cadenas .

La representación de cadena para la primera matriz sería "1,2" y la segunda sería "3,4" . Entonces, cuando +se encuentra el signo, no puede sumar matrices y luego concatenarlas como cadenas.

Doug
fuente
Sí, esa es la primera y única explicación que viene a la mente, pero ¿no es un comportamiento muy extraño? tal vez se está haciendo una operación / transformación oscura y desconocida, y me encantaría conocer los interiores: P
okeen
40

Las +cadenas concats, lo que convierte a las matrices de cadenas.

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

Para combinar matrices, use concat.

[1,2].concat([3,4])
[1,2,3,4]
Cohete Hazmat
fuente
21

En JavaScript, el operador de suma binaria ( +) realiza la suma numérica y la concatenación de cadenas. Sin embargo, cuando su primer argumento no es ni un número ni una cadena, lo convierte en una cadena (por lo tanto, " 1,2") y luego hace lo mismo con el segundo " 3,4" y los concatena en " 1,23,4".

Intente utilizar el método "concat" de matrices en su lugar:

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

Convierte las matrices individuales en cadenas y luego combina las cadenas.

tadman
fuente
14

Parece que JavaScript está convirtiendo sus matrices en cadenas y uniéndolas. Si desea agregar tuplas juntas, deberá usar un bucle o una función de mapa.

Adam Fabicki
fuente
14

[1,2]+[3,4] en JavaScript es lo mismo que evaluar:

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

y para resolver su problema, lo mejor sería agregar dos matrices en el lugar o sin crear una nueva matriz:

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

Está haciendo exactamente lo que le pediste que hiciera.

Lo que está agregando son referencias de matriz (que JS convierte en cadenas), no números como parece. Es un poco como agregar cadenas juntas: "hello " + "world"="hello world"

Jamie Dixon
fuente
55
jeje, SIEMPRE hace lo que le pedí. El problema es hacer la buena pregunta. Lo que me intriga es la interpretación toString () de las matrices cuando las agrega.
Okeen
8

Es porque, el operador + supone que los operandos son cadenas, si no son números. Por lo tanto, primero los convierte en cadenas y concatena para dar el resultado final, si no es un número. Además, no admite matrices.

Prashant Singh
fuente
2
El operador + NO puede asumir que los operandos son cadenas, porque 1 + 1 == 2, entre otros. Esto se debe a que '+' no está definido para las matrices, por lo que está encadenado a ellas.
Okeen
0

Algunas respuestas aquí han explicado cómo '1,23,4'ocurre la salida inesperada no deseada ( ) y algunas han explicado cómo obtener lo que suponen que es la salida deseada esperada ( [1,2,3,4]), es decir, la concatenación de matriz. Sin embargo, la naturaleza del resultado deseado esperado es en realidad algo ambiguo porque la pregunta original simplemente dice "Quería agregar los elementos de una matriz a otra ...". Eso podría significar array concatenación pero podría también Además media tupla (por ejemplo, aquí y aquí ), es decir la adición de los valores escalares de elementos en una matriz a los valores escalares de los elementos correspondientes en el segundo, por ejemplo, combinando [1,2]y [3,4]obtener [4,6].

Suponiendo que ambas matrices tienen la misma aridad / longitud, aquí hay una solución simple:

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

Otro resultado usando solo un simple signo "+" será:

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

Entonces algo como esto debería funcionar (¡pero!):

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

... pero convertirá la variable a de una matriz a cadena! Tenlo en mente.

Espinilla
fuente