Warum behandelt JavaScript die Plus- und Minusoperatoren zwischen Zeichenfolgen und Zahlen unterschiedlich?

73

Ich verstehe nicht, warum JavaScript so funktioniert.

console.log("1" + 1);
console.log("1" - 1);

Die erste Zeile gibt 11 und die zweite 0 aus. Warum behandelt JavaScript die erste als Zeichenfolge und die zweite als Zahl?

Nirgn
quelle
11
+1 - obwohl die Antwort , warum für jeden gewohnt mit JS offensichtlich ist, ist der Grund , warum die offensichtliche Antwort wahr ist über mein Verständnis ist nach wie vor - und ich glaube , ich bin nicht der einzige ... JS POLA versagt in vielerlei Hinsicht seufzen Stackoverflow .com / question / 9032856 /…
5
Ich denke,
DLeh
@ DLeh: Ich wollte gerade einen Link zu diesem Video posten: D
Rocket Hazmat
2
Auch verwandt: Ihre Sprache saugt
Simon Forsberg

Antworten:

105

Die Verkettung von +Zeichenfolgen erfolgt mit, sodass Javascript die erste numerische 1 in eine Zeichenfolge konvertiert und "1" und "1" zu "11" verkettet.

Sie können keine Subtraktion für Zeichenfolgen durchführen, daher konvertiert Javascript die zweite "1" in eine Zahl und subtrahiert 1 von 1, was zu Null führt.

Bernhard Hofmann
quelle
7
@ YuryTarabanko Okay. Die Verkettung (also keine Addition) setzt immer 2 Zeichenfolgen zusammen. Wenn Sie dies versuchen, tun [] + {}Sie dies im Grunde [].toString() + ({}).toString()(da JavaScript das betroffene Array und Objekt in eine Zeichenfolge konvertiert, bevor Sie sie verketten). Und, weil [].toString === ''und ({}).toString() === '[object Object]', Ihr Endergebnis für [] + {} === '[object Object]'. Es ist vollkommen logisch.
Joeytje50
4
@ Joeytje50 Richtig. Was ist mit {} + []? :) Gehen Sie voran, wenden Sie die gleiche Logik an :)
Yury Tarabanko
3
@YuryTarabanko Da Objekte und Arrays weder verkettet noch addiert werden können, wird das Array durch Zusammenfügen dieser beiden in dieser Reihenfolge in eine Zahl anstelle einer Zeichenfolge konvertiert, da sich das +Zeichen davor befindet (z. B. wie +new Dateder numerische Wert zurückgegeben wird) des DateObjekts (der UNIX-Zeitstempel) oder +truegibt den numerischen Wert von zurück true(d. h. 1). Aus diesem Grund wird der Zusatz {} + 0. Da das Objekt keinen numerischen Wert hat, wird dies zu dem +0, als das JavaScript ausgibt 0.
Joeytje50
4
@ Joeytje50 Haha, das ist nicht wirklich die gleiche Logik. Wenn "Objekte und Arrays weder verkettet noch addiert werden können", warum sollte dann [] + {}eine Verkettung durchgeführt werden, während {} + []dies nicht der Fall ist? Außerdem ist Ihre Aussage, dass "Objekt keinen numerischen Wert hat", falsch: +{}Gibt zurück NaN. Und NaN + 0ist es NaNnicht 0. Wie @Yury jedoch sagte, ist es sinnlos, JavaScript-Zwang vom Standpunkt praktischer Situationen oder des gesunden Menschenverstandes aus zu diskutieren.
Ajedi32
9
Nur für den Datensatz ist eine öffnende Klammer am Anfang einer Zeile in JavaScript ein Block, kein Objektliteral. so [] + {}und {} + []sind eigentlich zwei völlig unterschiedliche Aussagen
James Long
33

+ist nicht eindeutig. Es kann "verketten" oder "hinzufügen" bedeuten . Da eine Seite eine Zeichenfolge ist, bedeutet dies "verketten", daher ist das Ergebnis 11 (was übrigens als kleines Kind einer meiner Lieblingswitze war. Das und "1 + 1 = Fenster", as gezeigt , optisch: │┼│ ニ ⊞)

-hat jedoch nur eine Bedeutung: subtrahieren. Also subtrahiert es.

Diese Art von Problem tritt in anderen Sprachen wie PHP nicht auf, wo "verketten" .statt "nicht mehr eindeutig" ist +. Wieder andere Sprachen wie MySQL haben nicht einmal einen Verkettungsoperator, sondern verwenden CONCAT(a,b,c...).

Niet the Dark Absol
quelle
7
Eine andere Lösung, um dieses Problem (und viele andere Probleme, die auch in JavaScript auftreten) zu vermeiden, besteht darin, keine impliziten Konvertierungen zuzulassen. Python zum Beispiel gibt nur einen Fehler aus, wenn Sie etwas wie das oben Genannte versuchen, wodurch all diese unintuitiven Probleme überhaupt vermieden werden. Implizite Konvertierungen in einer dynamisch typisierten Sprache sind eine schreckliche Idee.
Voo
23

Weil die Spezifikation dies ausdrücklich vorschreibt. Seite 75. Beachten Sie den Unterschied zwischen 11.6.1 Schritten 5-8 und 11.6.2 Schritten 5-7.

11.6.1 - beschreibt, wie der Additionsoperator funktioniert

1-4. ...

5. Sei lprim ToPrimitive (lval).

6. Sei rprim ToPrimitive (rval).

7. Wenn Type (lprim) String oder Type (rprim) String ist, dann

7a. Gibt den String zurück, der das Ergebnis der Verkettung von ToString (lprim) gefolgt von ToString (rprim) ist.

8. Geben Sie das Ergebnis der Anwendung der Additionsoperation auf ToNumber (lprim) und ToNumber (rprim) zurück.

11.6.2 - beschreibt, wie der Subtraktionsoperator funktioniert

1-4. ...

5. Sei lnum ToNumber (lval).

6. Sei rnum ToNumber (rval).

7. Geben Sie das Ergebnis der Anwendung der Subtraktionsoperation auf lnum und rnum zurück

Zusammenfassung Im Falle einer Addition wird der zweite Operand ebenfalls in eine Zeichenfolge konvertiert, wenn einer der Operanden bei der Konvertierung in einen primitiven Wert ohne Hinweise plötzlich zu einer Zeichenfolge wird. Bei Subtraktion werden beide Operanden in eine Zahl umgewandelt.

Yury Tarabanko
quelle
1
@ Joeytje50 Zum Beispiel, versuchen Sie sich vorzustellen, warum [] + [] === "":) Liegt es an der Unklarheit über Verkettung oder Addition? LOL
Yury Tarabanko
3
+1, da dies die einzige maßgebliche Antwort ist. Der Rest mag eine nützliche Mnemonik sein, aber die ultimative Antwort lautet "weil die Spezifikation dies sagt", und sie sagt es, weil Brendan Eich es für eine gute Idee in diesen berüchtigten 10 Tagen hielt.
Matteo Italia
8

+ist sowohl ein Additionsoperator für numerische Variablen als auch ein Verkettungsoperator für Zeichenfolgen.

Immer wenn nach a eine Zeichenfolge steht +, verwendet Javascript den +als Verkettungsoperator und konvertiert (tippt) so viele Begriffe wie möglich um die Zeichenfolge, damit sie verkettet werden können. Das ist nur das Verhalten von Javascript. (Wenn Sie es versucht haben console.log(23 + 2 + "." + 1 + 5 + "02" + 02);, erhalten Sie das Ergebnis 25.15022. Die Nummer 02wurde 2vor der Verkettung in die Zeichenfolge eingegeben .

-kann nur ein Subtraktionsoperator sein. Wenn also eine Zeichenfolge angegeben wird, wird der Typ der Zeichenfolge implizit "1"in eine Zahl geändert 1. Wenn es das nicht tun "1" - 1würde, würde es keinen Sinn ergeben. Wenn Sie es versucht haben, erhalten console.log(23 + 2 + 1 + 5 - "02" + 03);Sie 32 - die Zeichenfolge 02wird in die Zahl umgewandelt 2. Der Begriff nach dem -muss in eine Zahl umgewandelt werden können; Wenn Sie es versucht haben, werden console.log(23 - 2 - "." - 1 - 5 - 02 - "02");Sie NaNzurückgegeben.

Noch wichtiger ist, wenn Sie es versucht haben console.log(23 + 2 + "." + 1 + 5 - "02" + 03);, wird ausgegeben 26.15, wo alles zuvor -als Zeichenfolge behandelt wurde (weil es eine Zeichenfolge enthält ".", und dann wird der Begriff nach dem -als Zahl behandelt.

Dayuloli
quelle
8

In JavaScript ** gibt es keinen dedizierten String-Verkettungsoperator. Der Additionsoperator +führt je nach Art der Operanden entweder eine Zeichenfolgenverkettung oder eine Addition durch:

"1" +  1  // "11"
 1  + "1" // "11"
 1  +  1  // 2

Es gibt kein Gegenteil von Verkettung (glaube ich) und der Subtraktionsoperator -führt nur eine Subtraktion durch, unabhängig von der Art der Operanden:

"1" -  1  // 0
 1  - "1" // 0
 1  -  1  // 0
"a" -  1  // NaN

** Der .Operator in PHP und der &Operator in VB sind dedizierte String-Verkettungsoperatoren.

Salman A.
quelle
3

Gemäß dem Standard-EcmaScript 262. Die Operatoren +und -verhalten sich unterschiedlich, wenn Zeichenfolgen beteiligt sind. Der erste konvertiert jeden Wert in eine Zeichenfolge. Der zweite konvertiert jeden Wert in eine Zahl.

Aus dem Standard:

Wenn Type (lprim) String oder Type (rprim) String ist, geben Sie den String zurück, der das Ergebnis der Verkettung von ToString (lprim) gefolgt von ToString (rprim) ist.

Diese Regeln implizieren, dass, wenn der Ausdruck einen Zeichenfolgenwert enthält, alle an der +Operation beteiligten Werte in eine Zeichenfolge konvertiert werden. Wenn der +Operator in JavaScript mit Zeichenfolgen verwendet wird, werden diese verkettet. Aus diesem Grund wird console.log("5"+1)"51" zurückgegeben. 1wird in eine Zeichenfolge konvertiert und dann werden "5" + "1" miteinander verkettet.

Die obige Regel gilt jedoch nicht für den -Betreiber. Wenn Sie ein verwenden, werden -alle Werte gemäß dem Standard in Zahlen konvertiert (siehe unten). Daher wird in diesem Fall in "5"konvertiert 5und dann 1subtrahiert.

Aus dem Standard:

5 Sei lnum ToNumber (lval).

6 Sei rnum ToNumber (rval).


Operatordefinition aus dem Standard-EcmaScript 262.

Betreiber + : http://www.ecma-international.org/ecma-262/5.1/#sec-11.6.1 Operator + Definition

Betreiber - : http://www.ecma-international.org/ecma-262/5.1/#sec-11.6.2 Operator - Definition

Giuseppe Pes
quelle
Mag es, wenn Leute Spezifikationen und Handbücher lesen und zitieren. Vielen Dank.
0

Mit Plus und einer Zeichenfolge geben ""Sie grundsätzlich eine Zeichenfolge zurück, da Sie eine Verkettung durchführen:

typeof ("" + 1 + 0)  // string
typeof (1 + 0)  // number

Wenn -Sie stattdessen verwenden, konvertieren Sie in eine Zahl, da eine Verkettung von Zeichenfolgen möglich ist:

typeof ("" - 1 + 0) // number
GibboK
quelle