Leere Arrays sind wahr, aber sie sind auch gleich falsch.
var arr = [];
console.log('Array:', arr);
if (arr) console.log("It's true!");
if (arr == false) console.log("It's false!");
if (arr && arr == false) console.log("...what??");
Ich denke, das liegt an der impliziten Konvertierung, die vom Gleichheitsoperator ausgeführt wird.
Kann jemand erklären, was hinter den Kulissen los ist?
javascript
Patonza
quelle
quelle
arr == true
dies nicht als wahr bewertet wird ;-)===
. Wenn Sie dann die Leere eines Arrays testen möchten, verwenden Siearr === []
arr === []
, da dies IMMER false zurückgibt, da die rechte Seite ein neues Array instanziiert und die Variable auf der linken Seite nicht auf etwas verweisen kann, das Sie gerade erstellt haben. Das Testen der Leere sollte durch Nachschlagen erfolgenarr.length === 0
.Antworten:
Sie testen hier verschiedene Dinge.
if (arr)
Das aufgerufene Objekt (Array ist eine Instanz von Object in JS) prüft, ob das Objekt vorhanden ist, und gibt true / false zurück.Wenn Sie aufrufen
if (arr == false)
, vergleichen Sie die Werte dieses Objekts mit dem primitivenfalse
Wert. Internarr.toString()
wird aufgerufen, was eine leere Zeichenfolge zurückgibt""
.Dies liegt daran, dass
toString
aufgerufene Array-RückgabenArray.join()
und leere Zeichenfolgen einer der falschen Werte in JavaScript sind.quelle
Boolean([])
zurückkommttrue
?In Bezug auf die Linie:
Vielleicht helfen diese:
Was meiner Meinung nach passiert, ist, dass der Boolesche
false
Wert zum0
Vergleich mit einem Objekt (der linken Seite) erzwungen wird . Das Objekt wird zu einer Zeichenfolge (der leeren Zeichenfolge) gezwungen. Dann wird die leere Zeichenfolge ebenfalls zu einer Zahl gezwungen, nämlich Null. Und so ist der endgültige Vergleich0
==0
, was isttrue
.Bearbeiten: Siehe diesen Abschnitt der Spezifikation für Details zu genau , wie das funktioniert.
Folgendes passiert ab Regel 1:
Die nächste geltende Regel lautet # 19:
Das Ergebnis von
ToNumber(false)
ist0
, also haben wir jetzt:Wieder sagt uns Regel 1, dass wir zu Schritt 14 springen sollen, aber der nächste Schritt, der tatsächlich gilt, ist # 21:
Das Ergebnis von
ToPrimitive([])
ist die leere Zeichenfolge, also haben wir jetzt:Wieder sagt uns Regel 1, dass wir zu Schritt 14 springen sollen, aber der nächste Schritt, der tatsächlich gilt, ist # 17:
Das Ergebnis von
ToNumber("")
ist0
, was uns übrig lässt mit:Jetzt haben beide Werte den gleichen Typ, sodass die Schritte von Nr. 1 bis Nr. 7 fortgesetzt werden. Darin heißt es:
Also kehren wir zurück
true
.In Kürze:
quelle
[] == 0
wahr. Ich verstehe, wie dies geschieht, basierend auf Ihrer Erklärung der Spezifikation, aber aus logischer Sicht scheint es ein seltsames Sprachverhalten zu sein.Um Waynes Antwort zu ergänzen und zu erklären, warum sie
ToPrimitive([])
zurückkehrt""
, sollten zwei mögliche Arten von Antworten auf die Warum-Frage in Betracht gezogen werden. Die erste Art der Antwort lautet: "Weil die Spezifikation besagt, dass sich JavaScript so verhält." In der ES5-Spezifikation, Abschnitt 9.1 , der das Ergebnis von ToPrimitive als Standardwert für ein Objekt beschreibt:Abschnitt 8.12.8 beschreibt die
[[DefaultValue]]
Methode. Diese Methode verwendet einen "Hinweis" als Argument, und der Hinweis kann entweder String oder Number sein. Um die Angelegenheit zu vereinfachen, indem auf einige Details verzichtet wird, gibt der Hinweis, wenn er String ist,[[DefaultValue]]
den Wert von zurück,toString()
falls vorhanden, und gibt einen primitiven Wert zurück, andernfalls den Wert vonvalueOf()
. Wenn der Hinweis Number ist, werden die Prioritäten vontoString()
undvalueOf()
umgekehrt, sodassvalueOf()
zuerst aufgerufen und der Wert zurückgegeben wird, wenn es sich um ein Grundelement handelt. Also, ob[[DefaultValue]]
das Ergebnis vontoString()
oder zurückgibtvalueOf()
für den angegebenen PreferredType für das Objekt zurückgegeben wird und ob diese Funktionen primitive Werte zurückgeben oder nicht.Die Standardobjektmethode gibt
valueOf()
nur das Objekt selbst zurück. Wenn eine Klasse die Standardmethode nicht überschreibt, wirdvalueOf()
nur das Objekt selbst zurückgegeben. Dies ist der Fall fürArray
.[].valueOf()
gibt das Objekt[]
selbst zurück. Da einArray
Objekt kein Grundelement ist, ist der[[DefaultValue]]
Hinweis irrelevant: Der Rückgabewert für ein Array ist der Wert vontoString()
.Um David Flanagans JavaScript zu zitieren : The Definitive Guide , das übrigens ein hervorragendes Buch ist, das der erste Ort sein sollte, an dem jeder Antworten auf diese Art von Fragen erhält:
Die zweite Art der Antwort auf die "Warum" -Frage, abgesehen von "Weil die Spezifikation sagt", gibt eine Erklärung dafür, warum das Verhalten aus der Designperspektive sinnvoll ist. Zu diesem Thema kann ich nur spekulieren. Wie würde man ein Array in eine Zahl umwandeln? Die einzig sinnvolle Möglichkeit, die ich mir vorstellen kann, wäre, ein leeres Array in 0 und jedes nicht leere Array in 1 zu konvertieren. Wie Waynes Antwort jedoch ergab, wird ein leeres Array für viele Arten von Vergleichen ohnehin in 0 konvertiert. Darüber hinaus fällt es schwer, sich einen sinnvollen primitiven Rückgabewert für Array.valueOf () vorzustellen. Man könnte also argumentieren, dass es nur sinnvoller ist
Array.valueOf()
, der Standard zu sein und das Array selbst zurückzugebentoString()
zu dem von ToPrimitive verwendeten Ergebnis führt. Es ist nur sinnvoller, ein Array in eine Zeichenfolge anstatt in eine Zahl zu konvertieren.Darüber hinaus ermöglicht diese Entwurfsentscheidung, wie aus dem Flanagan-Zitat hervorgeht, bestimmte Arten von vorteilhaften Verhaltensweisen. Zum Beispiel:
Mit diesem Verhalten können Sie ein Einzelelementarray mit Zahlen vergleichen und das erwartete Ergebnis erhalten.
quelle
quelle
In if (arr) wird es immer als true ausgewertet (ToBoolean), wenn arr ein Objekt ist, da alle Objekte in JavaScript wahr sind . (null ist kein Objekt!)
[] == false
wird im iterativen Ansatz bewertet. Wenn eine Seite von==
primitiv und die andere objekt ist, konvertiert sie zuerst Objekt in primitiv und konvertiert dann beide Seiten in Zahl, wenn beide Seiten nicht sindstring
(Zeichenfolgenvergleich wird verwendet, wenn beide Seiten Zeichenfolgen sind). Der Vergleich wird also wie folgt wiederholt:[] == false
->'' == false
->0 == 0
->true
.quelle
Beispiel:
Es passiert weil
[]
ist leeresArray
Objekt →ToPrimitive([])
→ "" →ToNumber("")
→0
ToNumber(false)
→ 0quelle
Ein Array mit Elementen (unabhängig davon, ob 0, false oder ein anderes leeres Array) wird immer
true
mit Abstract Abstract Equality Comparison aufgelöst==
.Mit einem strengen Gleichheitsvergleich
===
versuchen Sie jedoch, den Inhalt der Variablen sowie ihren Datentyp zu bewerten. Deshalb:quelle
Sie können ein JavaScript-Array leeren, indem Sie es auf ein neues Array verweisen und
list = []
die Elemente des aktuell referenzierten Arrays verwenden oder löschenlist.length = 0
.Quelle: JavaScript Empty Array
quelle
Keiner der oben genannten Punkte hat mir beim Versuch geholfen, das Mapping-Plugin knockout.js zu verwenden, vielleicht weil ein "leeres Array" nicht wirklich leer ist.
Am Ende habe ich verwendet:
data-bind="if: arr().length"
was den Trick gemacht hat.Dies ist spezifisch für das Knockout, nicht für die Frage des OP, aber vielleicht hilft es jemand anderem, hier in einer ähnlichen Situation zu surfen.
quelle