Leere Arrays scheinen gleichzeitig wahr und falsch zu sein
Lesezeit: 11 Minuten
Patonza
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 durchgeführt wird.
Kann jemand erklären, was hinter den Kulissen vor sich geht?
Hier ist ein ähnlicher Thread, der etwas Licht ins Dunkel bringen sollte: stackoverflow.com/questions/4226101/…
– Rion Williams
30. März 2011 um 20:01 Uhr
Beachten Sie, dass arr == true wertet nicht zu wahr 😉
– Michael Krelin – Hacker
30. März 2011 um 20:09 Uhr
Wow … gerade als du dachtest, du hättest das alles erledigt.
– Harfe
30. März 2011 um 20:14 Uhr
@DjebbZ beide ([] == []) und ([] === []) sollte immer als false ausgewertet werden! Arrays sind Objekte und werden durch Referenzgleichheit verglichen; zwei Array-Variablen können den gleichen Inhalt enthalten, sich aber dennoch unterscheiden.
– Joe Lee-Moyet
20. Dezember 2012 um 18:32 Uhr
Wenn Sie die Leerheit eines Arrays testen möchten, verwenden Sie NICHT 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 erfolgen arr.length === 0.
– Kyle Baker
22. August 2016 um 16:43 Uhr
Platzhalter
Sie testen hier verschiedene Dinge.
if (arr) called on object (Array ist eine Instanz von Object in JS) prüft, ob das Objekt vorhanden ist, und gibt true/false zurück.
Wenn du anrufst if (arr == false) du vergleichst Werte dieses Objekts und des Primitivs false Wert. Im Inneren, arr.toString() aufgerufen, die einen leeren String zurückgibt "".
Das ist weil toString aufgerufen bei Array-Rückgaben Array.join()und eine leere Zeichenfolge ist einer der falschen Werte in JavaScript.
Kannst du erklären warumBoolean([]) kehrt zurück true?
– Devy
2. Juni 2016 um 20:38 Uhr
Das ist Konvention, wenn Objekte in JS auf Boolean gezwungen werden, werden sie immer auf TRUE gezwungen. Schauen Sie sich die Tabelle “Boolescher Kontext” an unter: javascript.info/tutorial/object-conversion
Ich glaube, was passiert, ist, dass der boolesche Wert false dazu gezwungen wird 0 zum Vergleich mit einem Objekt (linke Seite). Das Objekt wird in einen String (den leeren String) umgewandelt. Dann wird auch der leere String in eine Zahl gezwungen, nämlich Null. Und so ist der letzte Vergleich 0 == 0welches ist true.
Hier ist, was passiert, beginnend mit Regel Nr. 1:
1. Wenn sich Typ(x) von Typ(y) unterscheidet, gehen Sie zu Schritt 14.
Die nächste Regel, die gilt, ist Nr. 19:
19. Wenn Type(y) Boolean ist, gib das Ergebnis des Vergleichs x == ToNumber(y) zurück.
Das Ergebnis von ToNumber(false) ist 0also haben wir jetzt:
[] == 0
Auch hier fordert uns Regel Nr. 1 auf, zu Schritt Nr. 14 zu springen, aber der nächste Schritt, der tatsächlich gilt, ist Nr. 21:
21. Wenn Type(x) Object ist und Type(y) entweder String oder Number ist, gib das Ergebnis des Vergleichs ToPrimitive(x)== y zurück.
Das Ergebnis von ToPrimitive([]) ist der leere String, also haben wir jetzt:
"" == 0
Auch hier fordert uns Regel Nr. 1 auf, zu Schritt Nr. 14 zu springen, aber der nächste Schritt, der tatsächlich gilt, ist Nr. 17:
17. Wenn Type(x) String ist und Type(y) Number ist, gib das Ergebnis des Vergleichs ToNumber(x)== y zurück.
Das Ergebnis von ToNumber("") ist 0was uns belässt:
0 == 0
Jetzt haben beide Werte den gleichen Typ, also gehen die Schritte von #1 bis #7 weiter, was besagt:
7. Wenn x derselbe Zahlenwert wie y ist, wird wahr zurückgegeben.
Also kehren wir zurück true.
In Kürze:
ToNumber(ToPrimitive([])) == ToNumber(false)
Tolle Referenz! Um Verwirrung zu vermeiden, könnte es hilfreich sein zu erwähnen, dass der Grund „die nächste anwendbare Regel ist Nr Werte verglichen werden.
– Sean die Bohne
8. Juli 2015 um 14:06 Uhr
Schöne Erklärung. Es ist mir rätselhaft, dass leere Arrays als wahr angesehen werden, 0 ist falsch, und doch [] == 0 ist wahr. Ich verstehe, wie dies geschieht, basierend auf Ihrer Erklärung der Spezifikation, aber es scheint aus logischer Sicht ein seltsames Sprachverhalten zu sein.
– groß_29
17. Januar 2018 um 22:16 Uhr
cjg
Um Waynes Antwort zu ergänzen und zu versuchen zu erklären, warum ToPrimitive([]) kehrt zurück "", lohnt es sich, zwei mögliche Arten von Antworten auf die „Warum“-Frage in Betracht zu ziehen. Die erste Art der Antwort lautet: „Weil die Spezifikation besagt, dass sich JavaScript so verhalten wird.“ In der ES5-Spezifikation Abschnitt 9.1die das Ergebnis von ToPrimitive als Standardwert für ein Objekt beschreibt:
Der Standardwert eines Objekts wird durch Aufrufen von abgerufen [[DefaultValue]]interne Methode des Objekts, wobei der optionale Hinweis PreferredType übergeben wird.
Abschnitt 8.12.8 beschreibt die [[DefaultValue]] Methode. Diese Methode akzeptiert einen „Hinweis“ als Argument, und der Hinweis kann entweder „String“ oder „Number“ sein. Um die Sache zu vereinfachen, indem auf einige Details verzichtet wird, wenn der Hint String ist, dann [[DefaultValue]] gibt den Wert von zurück toString() wenn es existiert und einen primitiven Wert zurückgibt und andernfalls den Wert von zurückgibt valueOf(). Wenn der Hinweis Nummer ist, sind die Prioritäten von toString() und valueOf() sind damit umgekehrt valueOf() wird zuerst aufgerufen und sein Wert zurückgegeben, wenn es sich um ein Primitiv handelt. Also, ob [[DefaultValue]] gibt das Ergebnis von zurück toString() oder valueOf() hängt vom angegebenen PreferredType für das Objekt ab und davon, ob diese Funktionen primitive Werte zurückgeben oder nicht.
Der Standard valueOf() Die Objektmethode gibt nur das Objekt selbst zurück, was bedeutet, dass, sofern eine Klasse die Standardmethode nicht überschreibt, valueOf() gibt nur das Objekt selbst zurück. Dies ist der Fall für Array. [].valueOf() gibt das Objekt zurück [] selbst. Seit ein Array Objekt ist kein Primitiv, das [[DefaultValue]] Hinweis ist irrelevant: Der Rückgabewert für ein Array ist der Wert von toString().
Die Details dieser Objekt-zu-Zahl-Konvertierung erklären, warum ein leeres Array in die Zahl 0 konvertiert wird und warum ein Array mit einem einzelnen Element auch in eine Zahl konvertiert werden kann. Arrays erben die Standardmethode valueOf(), die ein Objekt statt eines primitiven Werts zurückgibt, sodass die Umwandlung von Arrays in Zahlen auf der Methode toString() beruht. Leere Arrays werden in den leeren String konvertiert. Und die leere Zeichenfolge wird in die Zahl 0 konvertiert. Ein Array mit einem einzelnen Element wird in dieselbe Zeichenfolge konvertiert wie dieses eine Element. Wenn ein Array eine einzelne Zahl enthält, wird diese Zahl in eine Zeichenfolge und dann wieder in eine Zahl umgewandelt.
Die zweite Art der Antwort auf die „Warum“-Frage, außer „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. Erstens, wie würde man ein Array in eine Zahl umwandeln? Die einzige vernünftige Möglichkeit, die mir einfällt, wäre, ein leeres Array in 0 und jedes nicht leere Array in 1 zu konvertieren. Aber wie Waynes Antwort zeigte, wird ein leeres Array für viele Arten von Vergleichen sowieso in 0 konvertiert. Darüber hinaus ist es schwierig, sich einen vernünftigen primitiven Rückgabewert für Array.valueOf() vorzustellen. Man könnte also argumentieren, dass es einfach sinnvoller ist, es zu haben Array.valueOf() sei der Standardwert und gebe das Array selbst zurück, führend toString() das von ToPrimitive verwendete Ergebnis sein. Es ist einfach sinnvoller, ein Array in einen String statt in eine Zahl umzuwandeln.
Darüber hinaus ermöglicht diese Designentscheidung, wie das Flanagan-Zitat andeutet, bestimmte Arten von vorteilhaften Verhaltensweisen. Zum Beispiel:
var a = [17], b = 17, c=1;
console.log(a==b); // <= true
console.log(a==c); // <= false
Dieses Verhalten ermöglicht es Ihnen, ein Einzelelement-Array mit Zahlen zu vergleichen und das erwartete Ergebnis zu erhalten.
console.log('-- types: undefined, boolean, number, string, object --');
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof NaN); // number
console.log(typeof false); // boolean
console.log(typeof 0); // number
console.log(typeof ""); // string
console.log(typeof []); // object
console.log(typeof {}); // object
console.log('-- Different values: NotExist, Falsy, NaN, [], {} --');
console.log('-- 1. NotExist values: undefined, null have same value --');
console.log(undefined == null); // true
console.log('-- 2. Falsy values: false, 0, "" have same value --');
console.log(false == 0); // true
console.log(false == ""); // true
console.log(0 == ""); // true
console.log('-- 3. !NotExist, !Falsy, and !NaN return true --');
console.log(!undefined); // true
console.log(!null); // true
console.log(!false); // true
console.log(!""); // true
console.log(!0); // true
console.log(!NaN); // true
console.log('-- 4. [] is not falsy, but [] == false because [].toString() returns "" --');
console.log(false == []); // true
console.log([].toString()); // ""
console.log(![]); // false
console.log('-- 5. {} is not falsy, and {} != false, because {}.toString() returns "[object Object]" --');
console.log(false == {}); // false
console.log({}.toString()); // [object Object]
console.log(!{}); // false
console.log('-- Comparing --');
console.log('-- 1. string will be converted to number or NaN when comparing with a number, and "" will be converted to 0 --');
console.log(12 < "2"); // false
console.log("12" < "2"); // true
console.log("" < 2); // true
console.log('-- 2. NaN can not be compared with any value, even if NaN itself, always return false --');
console.log(NaN == NaN); // false
console.log(NaN == null); // false
console.log(NaN == undefined); // false
console.log(0 <= NaN); // false
console.log(0 >= NaN); // false
console.log(undefined <= NaN); // false
console.log(undefined >= NaN); // false
console.log(null <= NaN); // false
console.log(null >= NaN); // false
console.log(2 <= "2a"); // false, since "2a" is converted to NaN
console.log(2 >= "2a"); // false, since "2a" is converted to NaN
console.log('-- 3. undefined can only == null and == undefined, and can not do any other comparing even if <= undefined --');
console.log(undefined == null); // true
console.log(undefined == undefined); // true
console.log(undefined == ""); // false
console.log(undefined == false); // false
console.log(undefined <= undefined); // false
console.log(undefined <= null); // false
console.log(undefined >= null); // false
console.log(0 <= undefined); // false
console.log(0 >= undefined); // false
console.log('-- 4. null will be converted to "" when <, >, <=, >= comparing --');
console.log(12 <= null); // false
console.log(12 >= null); // true
console.log("12" <= null); // false
console.log("12" >= null); // true
console.log(0 == null); // false
console.log("" == null); // false
console.log('-- 5. object, including {}, [], will be call toString() when comparing --');
console.log(12 < {}); // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log(12 > {}); // false, since {}.toString() is "[object Object]", and then converted to NaN
console.log("[a" < {}); // true, since {}.toString() is "[object Object]"
console.log("[a" > {}); // false, since {}.toString() is "[object Object]"
console.log(12 < []); // false, since {}.toString() is "", and then converted to 0
console.log(12 > []); // true, since {}.toString() is "", and then converted to 0
console.log("[a" < []); // false, since {}.toString() is ""
console.log("[a" > []); // true, since {}.toString() is ""
console.log('-- 6. According to 4 and 5, we can get below weird result: --');
console.log(null < []); // false
console.log(null > []); // false
console.log(null == []); // false
console.log(null <= []); // true
console.log(null >= []); // true
Thomas
In if (arr) wird es immer als wahr ausgewertet (ToBoolean), wenn arr ein Objekt ist, weil Alle Objekte in JavaScript sind wahr. (Null ist kein Objekt!)
[] == false wird iterativ evaluiert. Zunächst, wenn eine Seite von == primitiv und die andere ein Objekt ist, wandelt es zuerst Objekt in primitiv um und dann beide Seiten in Zahl, wenn beide Seiten es nicht sind string (String-Vergleich wird verwendet, wenn beide Seiten Strings sind). Der Vergleich wird also wie folgt wiederholt: [] == false -> '' == false -> 0 == 0 -> true.
[] ist leer Array Objekt → ToPrimitive([]) → “” → ToNumber("") → 0
ToNumber(false) → 0
0 == 0 → wahr
Aldee
Ein Array mit Elementen (egal ob 0, false oder ein anderes leeres Array) wird immer aufgelöst true Verwenden von abstraktem Gleichheitsvergleich ==.
1. [] == false; // true, because an empty array has nothing to be truthy about
2. [2] == false; // false because it has at least 1 item
3. [false] == false; // also false because false is still an item
4. [[]] == false; // false, empty array is still an item
Aber mit einem strengen Gleichheitsvergleich ===Sie versuchen, den Inhalt der Variablen sowie ihren Datentyp auszuwerten, weshalb:
1. [] === false; // false, because an array (regardless of empty or not) is not strictly comparable to boolean `false`
2. [] === true; // false, same as above, cannot strictly compare [] to boolean `true`
3. [[]] === false; // true, because see #1
9159000cookie-checkLeere Arrays scheinen gleichzeitig wahr und falsch zu seinyes
Hier ist ein ähnlicher Thread, der etwas Licht ins Dunkel bringen sollte: stackoverflow.com/questions/4226101/…
– Rion Williams
30. März 2011 um 20:01 Uhr
Beachten Sie, dass
arr == true
wertet nicht zu wahr 😉– Michael Krelin – Hacker
30. März 2011 um 20:09 Uhr
Wow … gerade als du dachtest, du hättest das alles erledigt.
– Harfe
30. März 2011 um 20:14 Uhr
@DjebbZ beide ([] == []) und ([] === []) sollte immer als false ausgewertet werden! Arrays sind Objekte und werden durch Referenzgleichheit verglichen; zwei Array-Variablen können den gleichen Inhalt enthalten, sich aber dennoch unterscheiden.
– Joe Lee-Moyet
20. Dezember 2012 um 18:32 Uhr
Wenn Sie die Leerheit eines Arrays testen möchten, verwenden Sie NICHT
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
.– Kyle Baker
22. August 2016 um 16:43 Uhr