Warum ist in JavaScript "0" gleich "falsch", aber wenn es mit "wenn" getestet wird, ist es für sich genommen nicht falsch?

232

Folgendes zeigt, dass dies "0"in Javascript falsch ist:

>>> "0" == false
true

>>> false == "0"
true

Warum druckt der folgende "ha"?

>>> if ("0") console.log("ha")
ha
Unpolarität
quelle
47
"0"ist eine Zeichenfolge, und da sie nicht leer ist, wird sie als wahr ausgewertet.
Digital Plane
8
"0" === false [...] false
3
Schauen Sie sich Angus Crolls Artikel Wahrheit in Javascript an. javascriptweblog.wordpress.com/2011/02/07/…
Timrwood
8
'0'==falseaber '0' ist kein Falsey-Wert (ja, Javascript kann seltsam sein)
Linsey
5
@Linsey: Die ganze Sache "Falsch" und "Wahrhaftigkeit" sollte immer nur erklären, wie Werte in Boolesche Werte umgewandelt werden. Wenn Sie zwei Werte mit vergleichen ==, werden sie nie in Boolesche Werte konvertiert, sodass sie nicht zutreffen. (Die Regeln für die Konvertierung scheinen die Konvertierung in Zahlen zu begünstigen.)
Millimoose

Antworten:

251

Der Grund dafür ist, dass, wenn Sie dies explizit tun "0" == false, beide Seiten in Zahlen konvertiert werden und dann der Vergleich durchgeführt wird.

Wenn Sie Folgendes tun: if ("0") console.log("ha")wird der Zeichenfolgenwert getestet. Jede nicht leere Zeichenfolge ist true, während eine leere Zeichenfolge ist false.

Gleich (==)

Wenn die beiden Operanden nicht vom gleichen Typ sind , konvertiert JavaScript die Operanden und wendet dann einen strengen Vergleich an. Wenn einer der Operanden eine Zahl oder ein Boolescher Wert ist , werden die Operanden nach Möglichkeit in Zahlen konvertiert. Wenn einer der Operanden eine Zeichenfolge ist , wird der andere Operand nach Möglichkeit in eine Zeichenfolge konvertiert. Wenn beide Operanden Objekte sind , vergleicht JavaScript interne Referenzen, die gleich sind, wenn Operanden auf dasselbe Objekt im Speicher verweisen.

(Von Vergleichsoperatoren im Mozilla Developer Network)

jdi
quelle
348

Tabellen mit dem Problem:

wahrheitsgemäße wenn Aussage

und == wahrheitsgemäße Vergleiche aller Objekttypen in Javascript

Moral der Geschichte verwenden === strenge Gleichheit, die geistige Gesundheit zeigt

Guthaben für die Tabellengenerierung: https://github.com/dorey/JavaScript-Equality-Table

Joe
quelle
2
Es ist viel sinnvoller mit einer anderen Reihenfolge von Werten gist.github.com/kirilloid/8165660
kirilloid
3
Wenn jemand von nun an sagt, dass er niemals strenge Vergleichsoperatoren verwendet, werde ich ihn mit diesen Tabellen konfrontieren und ihn zum Weinen bringen. Ich bin mir immer noch nicht sicher, ob ich das Konzept NaNverstehe. Ich meine, typeof NaN // numberaber NaN === NaN // false, hmm ...
Justus Romijn
4
Ein Freund von mir hat f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html erstellt - die gleichen Grafiken wie oben, aber etwas einfacher zu lesen.
Lucy Bain
@JustusRomijn Es gibt mehrere Werte, die dargestellt werden NaNmüssen. Wenn Sie also 2 NaNs vergleichen, haben sie unterschiedliche Werte (denke ich). Lesen Sie das erste Zitat hier .
Cychoi
4
Diese Tabellen haben einen Fehler. Weder ==noch ===Betreiber für die [], {}, [[]], [0]und [1]Werte auswerten nicht auf true. Ich meine [] == []und [] === []auch falsch.
Herbertusz
38

Es ist nach Spezifikation.

12.5 Die if-Anweisung 
..... .....

2. Wenn ToBoolean (GetValue (exprRef)) wahr ist, dann 
ein. Geben Sie das Ergebnis der Auswertung der ersten Anweisung zurück.
3. Sonst 
....

ToBoolean ist laut Spezifikation

Die abstrakte Operation ToBoolean konvertiert ihr Argument gemäß Tabelle 11 in einen Wert vom Typ Boolean:

Und diese Tabelle sagt dies über Zeichenfolgen:

Geben Sie hier die Bildbeschreibung ein

Das Ergebnis ist falsch, wenn das Argument der leere String ist (seine Länge ist Null). Andernfalls ist das Ergebnis wahr

Um zu erklären, warum "0" == falseSie den Gleichheitsoperator lesen sollten, der angibt, dass er seinen Wert aus der abstrakten Operation erhält, GetValue(lref)stimmt dies für die rechte Seite überein.

Welches beschreibt diesen relevanten Teil als:

wenn IsPropertyReference (V), dann 
ein. Wenn HasPrimitiveBase (V) falsch ist, sei get die interne Methode [[Get]] der Basis, andernfalls sei get
sei die spezielle [[Get]] interne Methode, die unten definiert ist. 
b. Gibt das Ergebnis des Aufrufs der internen Methode get unter Verwendung von base als diesen Wert und der Übergabe zurück
GetReferencedName (V) für das Argument

Mit anderen Worten, eine Zeichenfolge hat eine primitive Basis, die die interne get-Methode zurückruft und am Ende falsch aussieht.

Wenn Sie Dinge mit der Operation GetValue auswerten möchten, verwenden Sie ==, wenn Sie mit der Operation bewerten möchten ToBoolean, verwenden Sie ===(auch als "strenger" Gleichheitsoperator bezeichnet).

Inkognito
quelle
"a string has a primitive base, which calls back the internal get method and ends up looking false"Gilt das für alle Saiten?
Aziz Punjani
@Interstellar_Coder Section 8.12.3: [[Get]] (P)beschreibt, wie es funktioniert. Dies gilt nur für Fälle, in denen die Zeichenfolge 0 ist, da schließlich eine Reihe anderer interner Aufrufe ausgeführt werden, bei denen festgestellt wird, GetOwnPropertydass "was auch immer" eine Dateneigenschaft ist, die diesen Wert dann vollständig zurückgibt. Deshalb ist "0" falsch und "bla" ist wahr. Schauen Sie sich einige von Douglas Crockfords Videos im Yahoo Developer Theatre an. Er beschreibt "Wahrhaftigkeit" in JavaScript etwas weniger komplex als ich. Wenn Sie verstehen, was "wahr" und "falsch" bedeutet, werden Sie die Antwort von Bobince sofort verstehen.
Inkognito
1
Wo finde ich die Spezifikation?
user985366
12

Es ist PHP, wo die Zeichenfolge "0"falsch ist (falsch, wenn sie im booleschen Kontext verwendet wird). In JavaScript sind alle nicht leeren Zeichenfolgen wahr.

Der Trick besteht darin, dass ==ein Boolescher Wert in einem booleschen Kontext nicht ausgewertet wird, sondern in eine Zahl konvertiert wird. Bei Zeichenfolgen wird dies als Dezimalanalyse analysiert. Sie erhalten also die Zahl 0anstelle der Booleschen Wahrheit true.

Dies ist ein wirklich schlechtes Sprachdesign und einer der Gründe, warum wir versuchen, den unglücklichen ==Operator nicht zu verwenden . Verwenden Sie ===stattdessen.

Bobince
quelle
7
// I usually do this:

x = "0" ;

if (!!+x) console.log('I am true');
else      console.log('I am false');

// Essentially converting string to integer and then boolean.
Thava
quelle
4

Ihre Anführungszeichen 0machen es zu einer Zeichenfolge, die als wahr bewertet wird.

Entfernen Sie die Anführungszeichen und es sollte funktionieren.

if (0) console.log("ha") 
Jason Gennaro
quelle
Richtig, nicht darüber, wie man "es zum Laufen bringt", sondern die Frage lautet eher: "Warum hat es sich so verhalten?"
Unpolarität
1

Der "if" -Ausdruck prüft die Wahrhaftigkeit, während der Doppelgleichheitsprüfung die typunabhängige Äquivalenz prüft. Eine Saite ist immer wahr, wie andere hier betont haben. Wenn das Doppelgleiche beide Operanden auf Wahrhaftigkeit prüft und dann die Ergebnisse vergleicht, erhalten Sie das Ergebnis, das Sie intuitiv angenommen haben, d ("0" == true) === true. H. Wie Doug Crockford in seinem ausgezeichneten JavaScript sagt : The Good Parts , "sind die Regeln, nach denen [== die Typen seiner Operanden erzwingt] kompliziert und unvergesslich ... Der Mangel an Transitivität ist alarmierend." Es genügt zu sagen, dass einer der Operanden typgezwungen ist, um mit dem anderen übereinzustimmen, und dass "0" als numerische Null interpretiert wird.

Jollymorph
quelle
1

== Der Gleichheitsoperator wertet die Argumente aus, nachdem sie in Zahlen konvertiert wurden. So String Null „0“ Number - Datentyp und boolean false umgewandelt wird Nummer 0 umgewandelt , so

"0" == false // true

Gleiches gilt für `

false == "0" //true

=== Strikte Gleichheitsprüfung wertet die Argumente mit dem ursprünglichen Datentyp aus

"0" === false // false, because "0" is a string and false is boolean

Gleiches gilt für

false === "0" // false

Im

if("0") console.log("ha");

Die Zeichenfolge "0" wird nicht mit Argumenten verglichen, und die Zeichenfolge ist ein wahrer Wert, bis oder sofern sie nicht mit Argumenten verglichen wird. Es ist genau so

if(true) console.log("ha");

Aber

if (0) console.log("ha"); // empty console line, because 0 is false

`

Vishnu K. Panicker
quelle
1

Dies liegt daran, dass JavaScript in booleschen Kontexten und in Ihrem Code Typzwang verwendet

if ("0") 

wird in booleschen Kontexten zu true gezwungen.

Es gibt andere wahrheitsgemäße Werte in Javascript, die in booleschen Kontexten zu true gezwungen werden und daher den if-Block ausführen: -

if (true)
if ({})
if ([])
if (42)
if ("0")
if ("false")
if (new Date())
if (-42)
if (12n)
if (3.14)
if (-3.14)
if (Infinity)
if (-Infinity)
Sachin
quelle