Warum ist [1,2] + [3,4] = "1,23,4" in JavaScript?

405

Ich wollte die Elemente eines Arrays in ein anderes einfügen, also habe ich Folgendes versucht:

[1,2] + [3,4]

Es antwortete mit:

"1,23,4"

Was ist los?

okeen
quelle
1
Hier ist eine Frage zu diesem Thema: stackoverflow.com/questions/1724255/why-does-2-2-in-javascript
Xavi
29
Ah-ha-ha, sadistischer Interviewer kann sogar so etwas fragen - was dies zurückgeben wird [1,2] + [5,6,7] [1,2]. Warum?
Shabunc
9
Ich denke, [1,2] + [3,4] war diese Woche nach Alarm ('Mist') der am meisten bewertete Ausdruck in Firebug.
Okeen
6
Willst du lachen ? Versuchen Sie [] + [], {} + [], {} + {} und [] + {}
Intrepidd
1
@shabunc - Erklären Sie bitte, warum dies so [5,6,7][1,2]ist, 7weil das letzte Element im zweiten Array verwendet wird. Oo
vsync

Antworten:

518

Der +Operator ist nicht für Arrays definiert .

Was passiert ist, dass Javascript Arrays in Strings konvertiert und diese verkettet.

 

Aktualisieren

Da diese Frage und folglich meine Antwort viel Aufmerksamkeit erhält, hielt ich es für nützlich und relevant, einen Überblick darüber zu haben, wie die+ Bediener im Allgemeinen auch verhält.

Also, hier geht es.

Mit Ausnahme von E4X und implementierungsspezifischem Material verfügt Javascript (ab ES5) über 6 integrierte Datentypen :

  1. Nicht definiert
  2. Null
  3. Boolescher Wert
  4. Nummer
  5. String
  6. Objekt

Beachten Sie, dass, obwohl typeof etwas verwirrend object für Null undfunction für aufrufbare Objekte ist, eigentlich kein Objekt ist und streng genommen in spezifikationskonformen Javascript-Implementierungen alle Funktionen als Objekte betrachtet werden.

Das ist richtig - Javascript hat keine primitiven Arrays als solche; Es werden nur Instanzen eines Objekts aufgerufenArray mit etwas syntaktischem Zucker , um den Schmerz zu lindern.

Das Hinzufügen von mehr zur Verwirrung, Wrapper - Entitäten wie new Number(5), new Boolean(true)und new String("abc")sind alleobject Typen, keine Zahlen, Boolesche Werte oder Strings als man erwarten könnte. Trotzdem für arithmetische Operatoren Numberund Booleanverhalten sich wie Zahlen.

Einfach, oder? Mit all dem aus dem Weg können wir zur Übersicht selbst übergehen.

Verschiedene Ergebnistypen +nach Operandentypen

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

* gilt für Chrome13, FF6, Opera11 und IE9. Das Überprüfen anderer Browser und Versionen bleibt dem Leser als Übung überlassen.

Anmerkung: Wie bereits von aus CMS , für bestimmte Fälle von Objekten wie Number, Booleanund benutzerdefiniert diejenigen , die +Betreiber nicht unbedingt ein String Ergebnis. Dies kann abhängig von der Implementierung der Konvertierung von Objekt zu Primitiv variieren. Zum Beispiel die var o = { valueOf:function () { return 4; } };Bewertung von o + 2;Produkten 6, a number, die Bewertung von o + '2'Produkten'42' , a string.

Um zu sehen, wie die Übersichtstabelle erstellt wurde, besuchen Sie http://jsfiddle.net/1obxuc7m/

Saul
quelle
244

JavaScript + Operator dient zwei Zwecken: Hinzufügen von zwei Zahlen oder Verbinden von zwei Zeichenfolgen. Es hat kein spezifisches Verhalten für Arrays, daher werden sie in Zeichenfolgen konvertiert und dann verbunden.

Wenn Sie zwei Arrays verbinden möchten, um ein neues zu erstellen, verwenden Sie stattdessen die folgende .concatMethode :

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

Wenn Sie alle Elemente von einem Array zu einem anderen effizient hinzufügen möchten, müssen Sie die .push-Methode verwenden :

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]

Das Verhalten des +Bedieners ist in Abschnitt 11.6.1 von ECMA-262 5e definiert :

11.6.1 Der Additionsoperator (+)

Der Additionsoperator führt entweder eine Zeichenfolgenverkettung oder eine numerische Addition durch. Die Produktion AdditiveExpression : AdditiveExpression + MultiplicativeExpressionwird wie folgt bewertet:

  1. Sei lrefdas Ergebnis der Bewertung AdditiveExpression.
  2. Lass lvalseinGetValue(lref).
  3. Sei rrefdas Ergebnis der Bewertung MultiplicativeExpression.
  4. Lass rvalsein GetValue(rref).
  5. Lass lprimsein ToPrimitive(lval).
  6. Lass rprimsein ToPrimitive(rval).
  7. Wenn Type(lprim)ist Stringoder Type(rprim)ist String, dann
    1. Gibt den String zurück, der das Ergebnis der Verkettung ist, ToString(lprim)gefolgt vonToString(rprim)
  8. Geben Sie das Ergebnis der Anwendung der Additionsoperation auf ToNumber(lprim)und zurück ToNumber(rprim). Siehe den Hinweis unten 11.6.3.

Sie können sehen, dass jeder Operand konvertiert wird ToPrimitive. Wenn wir weiterlesen, können wir feststellen, dass ToPrimitiveArrays immer in Strings konvertiert werden, was zu diesem Ergebnis führt.

Jeremy Banks
quelle
7
+1, da diese Antwort nicht nur das Problem erklärt, sondern auch erklärt, wie man es richtig macht.
Schnaader
3
Hier gibt es ein bisschen Zeit, aber ich stimme Schnaader zu. Die besten Antworten erklären das Problem / den Fehler / das Verhalten, nach dem gefragt wird, und zeigen dann, wie das beabsichtigte Ergebnis erzielt werden kann. +1
Matthewdunnam
1
Warum würden Sie die ausführlichere Array.prototype.push.apply(data, [3, 4])anstelle von verwenden data.concat([3,4])?
evilcelery
5
@evilcelery: Sie dienen verschiedenen Zwecken. concaterzeugt ein neues Array, der längere Aufruf erweitert effizient ein vorhandenes Array.
Jeremy Banks
1
Sie können [].push.apply(data, [3,4])für etwas weniger Ausführlichkeit verwenden. Auch das ist garantiert resistent gegen andere Menschen, die den Wert von ändern Array.
Sam Tobin-Hochstadt
43

Es fügt die beiden Arrays hinzu, als wären sie Strings .

Die Zeichenfolgendarstellung für das erste Array wäre "1,2" und das zweite wäre "3,4" . Wenn das +Zeichen gefunden wird, kann es keine Arrays summieren und sie dann als Zeichenfolgen verketten.

Doug
quelle
Ja, das ist die erste und einzigartige Erklärung, die dem Geist einfällt, aber ist das nicht ein sehr seltsames Verhalten? Vielleicht wird eine dunkle, unbekannte Operation / Transformation durchgeführt, und ich würde gerne die
Innereien
40

Die +Concats-Zeichenfolgen konvertieren die Arrays in Zeichenfolgen.

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

Verwenden Sie zum Kombinieren von Arrays concat.

[1,2].concat([3,4])
[1,2,3,4]
Rakete Hazmat
quelle
21

In JavaScript führt der binäre Additionsoperator ( +) sowohl die numerische Addition als auch die Verkettung von Zeichenfolgen durch. Wenn das erste Argument jedoch weder eine Zahl noch eine Zeichenfolge ist, konvertiert es es in eine Zeichenfolge (daher " 1,2"), dann macht es dasselbe mit dem zweiten " 3,4" und verkettet sie mit " 1,23,4".

Versuchen Sie stattdessen die "concat" -Methode von Arrays:

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

Es konvertiert die einzelnen Arrays in Strings und kombiniert dann die Strings.

Tadman
quelle
14

Es sieht so aus, als würde JavaScript Ihre Arrays in Strings verwandeln und zusammenfügen. Wenn Sie Tupel hinzufügen möchten, müssen Sie eine Schleife oder eine Kartenfunktion verwenden.

Adam Fabicki
quelle
14

[1,2]+[3,4] in JavaScript ist dasselbe wie auswerten:

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

Um Ihr Problem zu lösen, sollten Sie am besten zwei Arrays direkt hinzufügen oder kein neues Array erstellen:

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

Es macht genau das, worum Sie es gebeten haben.

Was Sie zusammenfügen, sind Array-Referenzen (die JS in Zeichenfolgen konvertiert), keine Zahlen, wie es scheint. Es ist ein bisschen wie das Hinzufügen von Zeichenfolgen: "hello " + "world"="hello world"

Jamie Dixon
quelle
5
hehe, es macht IMMER das, was ich gefragt habe. Das Problem ist, die gute Frage zu stellen. Was mich fasziniert, ist die toString () -Interpretation der Arrays, wenn Sie sie hinzufügen.
Okeen
8

Dies liegt daran, dass der Operator + davon ausgeht, dass die Operanden Zeichenfolgen sind, wenn es sich nicht um Zahlen handelt. Also konvertiert es sie zuerst in String und Concats, um das Endergebnis zu erhalten, wenn es keine Zahl ist. Außerdem werden Arrays nicht unterstützt.

Prashant Singh
quelle
2
Der Operator + kann NICHT annehmen, dass die Operanden Zeichenfolgen sind, da unter anderem 1 + 1 == 2 ist. Das liegt daran, dass '+' nicht für Arrays definiert ist, also für String-s.
Okeen
0

Einige Antworten hier haben erklärt, wie die unerwartete unerwünschte Ausgabe ( '1,23,4') geschieht, und einige haben erklärt, wie man das erhält, was sie für die erwartete gewünschte Ausgabe ( [1,2,3,4]) halten, dh die Array-Verkettung. Die Art der erwarteten gewünschten Ausgabe ist jedoch tatsächlich etwas mehrdeutig, da in der ursprünglichen Frage lediglich "Ich wollte die Elemente eines Arrays zu einem anderen hinzufügen ..." angegeben wird. Dies könnte eine Array-Verkettung bedeuten, aber es könnte auch eine Tupeladdition bedeuten (z. B. hier und hier ), dh das Hinzufügen der Skalarwerte von Elementen in einem Array zu den Skalarwerten der entsprechenden Elemente im zweiten Array, z. B. Kombinieren [1,2]und [3,4]Erhalten [4,6].

Angenommen, beide Arrays haben dieselbe Arität / Länge, ist hier eine einfache Lösung:

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

Ein weiteres Ergebnis mit nur einem einfachen "+" - Zeichen ist:

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

So etwas sollte funktionieren (aber!):

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

... aber es wird die Variable a von einem Array in einen String konvertieren! Denken Sie daran.

Mitesser
quelle