Perché [1,2] + [3,4] = "1,23,4" in JavaScript?


405

Volevo aggiungere gli elementi di un array in un altro, quindi ho provato questo:

[1,2] + [3,4]

Ha risposto con:

"1,23,4"

Cosa sta succedendo?


1
Ecco una domanda relativa a questo argomento: stackoverflow.com/questions/1724255/why-does-2-2-in-javascript
Xavi

29
Ah-ah-ah, l'intervistatore sadico può anche chiedere qualcosa del genere: cosa restituirà [1,2] + [5,6,7] [1,2]. perché?
shabunc,

9
Penso che [1,2] + [3,4] sia stata l'espressione più valutata in firebug questa settimana, dopo l'allerta ('schifezza').
okeen

6
Vuoi ridere ? Prova [] + [], {} + [], {} + {} e [] + {}
Intrepidd

1
@shabunc - attenzione a spiegare perché [5,6,7][1,2]è 7perché utilizza l'ultimo elemento nel secondo array. Oo
vsync,

Risposte:


518

L' +operatore non è definito per le matrici .

Quello che succede è che Javascript converte le matrici in stringhe e le concatena.

 

Aggiornare

Dato che questa domanda e, di conseguenza, la mia risposta stanno suscitando molta attenzione, ho ritenuto utile e pertinente avere una visione d'insieme su come l' +operatore si comporta anche in generale.

Quindi, eccola qui.

Escludendo E4X e elementi specifici dell'implementazione, Javascript (a partire da ES5) ha 6 tipi di dati integrati :

  1. Non definito
  2. Nullo
  3. booleano
  4. Numero
  5. Corda
  6. Oggetto

Si noti che sebbene typeof restituisca un po 'di confusione object per Null e functionper oggetti richiamabili, Null in realtà non è un oggetto e in senso stretto, nelle implementazioni Javascript conformi alle specifiche tutte le funzioni sono considerate come oggetti.

Esatto - Javascript non ha matrici primitive come tali; solo le istanze di un Oggetto chiamate Arraycon dello zucchero sintattico per alleviare il dolore.

Aggiungendo altro alla confusione, entità wrapper come new Number(5), new Boolean(true)e new String("abc")sono tutte di objecttipo, non numeri, valori booleani o stringhe come ci si potrebbe aspettare. Tuttavia per gli operatori aritmetici Numbere Booleancomportarsi come numeri.

Facile, eh? Con tutto ciò, possiamo passare alla panoramica stessa.

Diversi tipi di risultati per tipo di +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 | 

* si applica a Chrome13, FF6, Opera11 e IE9. Il controllo di altri browser e versioni viene lasciato come esercizio per il lettore.

Nota: Come sottolineato da CMS , per alcuni casi di oggetti quali Number, Booleane quelli personalizzati l' +operatore non deve necessariamente produrre un risultato stringa. Può variare a seconda dell'implementazione della conversione da oggetto a primitiva. Ad esempio, var o = { valueOf:function () { return 4; } };valutare o + 2;produce 6, a number, valutare o + '2'produce '42', a string.

Per vedere come è stata generata la tabella di panoramica, visitare http://jsfiddle.net/1obxuc7m/


244

L' +operatore JavaScript ha due scopi: aggiungere due numeri o unire due stringhe. Non ha un comportamento specifico per gli array, quindi li sta convertendo in stringhe e poi li unisce.

Se si desidera unire due array per produrne uno nuovo, utilizzare invece il .concatmetodo :

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

Se si desidera aggiungere in modo efficiente tutti gli elementi da un array all'altro, è necessario utilizzare il metodo .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]

Il comportamento +dell'operatore è definito nella Sezione 11.6.1 dell'ECMA-262 5e :

11.6.1 Operatore aggiunta (+)

L'operatore addizione esegue la concatenazione di stringhe o l'aggiunta numerica. La produzione AdditiveExpression : AdditiveExpression + MultiplicativeExpressionviene valutata come segue:

  1. Lascia che lrefsia il risultato della valutazione AdditiveExpression.
  2. Lascia lvalstare GetValue(lref).
  3. Lascia che rrefsia il risultato della valutazione MultiplicativeExpression.
  4. Lascia rvalstare GetValue(rref).
  5. Lascia lprimstare ToPrimitive(lval).
  6. Lascia rprimstare ToPrimitive(rval).
  7. Se Type(lprim)è Stringo Type(rprim)è String, allora
    1. Restituisce la stringa risultante dalla concatenazione ToString(lprim)seguita daToString(rprim)
  8. Restituisce il risultato dell'applicazione dell'operazione di aggiunta a ToNumber(lprim)e ToNumber(rprim). Vedi la nota sotto 11.6.3.

Puoi vedere che ogni operando viene convertito ToPrimitive. Leggendo ulteriormente possiamo scoprire che ToPrimitiveconvertirà sempre le matrici in stringhe, producendo questo risultato.


7
+1 come questa risposta non solo spiega il problema, ma spiega anche come farlo nel modo giusto.
Schnaader,

3
c'è un po 'di tmi qui, ma sono d'accordo con Schnaader. Le migliori risposte spiegano il problema / errore / comportamento richiesto, quindi mostra come produrre il risultato desiderato. +1
matthewdunnam,

1
Perché dovresti usare più prolisso Array.prototype.push.apply(data, [3, 4])invece di data.concat([3,4])?
evilcelery,

5
@evilcelery: servono a scopi diversi. concatproduce un nuovo array, la chiamata più lunga estende in modo efficiente un array esistente .
Jeremy Banks,

1
Puoi usarlo [].push.apply(data, [3,4])per un po 'meno verbosità. Inoltre, questo è garantito per resistere ad altre persone che cambiano il valore di Array.
Sam Tobin-Hochstadt,

43

Aggiunge i due array come se fossero stringhe .

La rappresentazione di stringa per il primo array sarebbe "1,2" e il secondo sarebbe "3,4" . Quindi, quando +viene trovato il segno, non può sommare le matrici e quindi concatenarle come stringhe.


Sì, questa è la prima e unica spiegazione che viene alla mente ma non è un comportamento molto strano? forse c'è qualche oscura operazione sconosciuta / trasformazione in corso, e mi piacerebbe conoscere gli interni: P
okeen,

40

Le +stringhe concats, quindi converte le matrici di stringhe.

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

Per combinare le matrici, utilizzare concat.

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

21

In JavaScript, l'operatore di aggiunta binaria ( +) esegue sia l'aggiunta numerica sia la concatenazione di stringhe. Tuttavia, quando il suo primo argomento non è né un numero né una stringa, lo converte in una stringa (quindi " 1,2"), quindi fa lo stesso con il secondo " 3,4" e li concatena in " 1,23,4".

Prova invece a utilizzare il metodo "concat" di array:

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

19

Sta convertendo le singole matrici in stringhe, quindi combinando le stringhe.


14

Sembra che JavaScript stia trasformando le tue matrici in stringhe e le unendo insieme. Se si desidera aggiungere insieme le tuple, è necessario utilizzare un ciclo o una funzione della mappa.


14

[1,2]+[3,4] in JavaScript equivale a valutare:

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

e quindi per risolvere il tuo problema, la cosa migliore sarebbe aggiungere due array sul posto o senza creare un nuovo array:

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

12

Sta facendo esattamente quello che gli hai chiesto di fare.

Quello che stai sommando sono riferimenti di array (che JS converte in stringhe), non numeri come sembra. È un po 'come aggiungere stringhe insieme: "hello " + "world"="hello world"


5
hehe, fa sempre quello che ho chiesto. Il problema è porre la buona domanda. Ciò che mi incuriosisce è l'interpretazione toString () degli array quando li aggiungi.
okeen


8

È perché, l'operatore + presuppone che gli operandi siano una stringa, se non sono numeri. Quindi, prima li converte in stringa e si concede per dare il risultato finale, se non è un numero. Inoltre, non supporta gli array.


2
L'operatore + NON può presumere che gli operandi siano stringhe, perché 1 + 1 == 2, tra gli altri. È perché '+' non è definito per le matrici, quindi per stringerle.
okeen

0

Alcune risposte qui hanno spiegato come '1,23,4'avviene l' output indesiderato imprevisto ( ) e alcuni hanno spiegato come ottenere quello che si presume sia l'output desiderato atteso ( [1,2,3,4]), ovvero la concatenazione di array. Tuttavia, la natura dell'output desiderato atteso è in realtà un po 'ambigua perché la domanda originale afferma semplicemente "Volevo aggiungere gli elementi di un array in un altro ...". Ciò potrebbe significare la concatenazione di array ma potrebbe anche significare l'aggiunta di tuple (ad esempio qui e qui ), vale a dire aggiungere i valori scalari degli elementi in un array ai valori scalari degli elementi corrispondenti nel secondo, ad esempio combinando [1,2]e [3,4]ottenere [4,6].

Supponendo che entrambi gli array abbiano la stessa arità / lunghezza, ecco una soluzione semplice:

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]


-1

Un altro risultato usando solo un semplice segno "+" sarà:

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

Quindi qualcosa del genere dovrebbe funzionare (ma!):

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

... ma convertirà la variabile a da una matrice a stringa! Tienilo a mente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.