Puste tablice są prawdziwe, ale są również równe false.
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??");
Wydaje mi się, że wynika to z niejawnej konwersji obsługiwanej przez operatora równości.
Czy ktoś może wyjaśnić, co dzieje się za kulisami?
javascript
Patonza
źródło
źródło
arr == true
to nie zgadza się z prawdą ;-)===
. Jeśli chcesz przetestować pustość tablicy, użyjarr === []
arr === []
, ponieważ ZAWSZE zwróci ona wartość false, ponieważ prawa strona tworzy nową tablicę, a zmienna po lewej nie może odnosić się do czegoś, co właśnie utworzyłeś. Testowanie pustki należy wykonać, podnosząc wzrokarr.length === 0
.Odpowiedzi:
Testujesz tutaj różne rzeczy.
if (arr)
wywołany na obiekcie (Array jest instancją Object w JS) sprawdzi, czy obiekt jest obecny i zwróci true / false.Podczas wywoływania
if (arr == false)
porównujesz wartości tego obiektu z pierwotnąfalse
wartością.arr.toString()
Nazywa się wewnętrznie, co zwraca pusty ciąg""
.Wynika to z tego, że
toString
wywołana tablica zwracaArray.join()
, a pusty ciąg znaków jest jedną z wartości fałszowania w JavaScript.źródło
Boolean([])
powracatrue
?Jeśli chodzi o linię:
Może te pomogą:
Moim zdaniem dzieje się tak, że wartość logiczna
false
jest zmuszana do0
porównania z obiektem (lewa strona). Obiekt jest przymuszany do łańcucha (pusty łańcuch). Następnie pusty ciąg jest również przymuszany do liczby, a mianowicie do zera. Tak więc końcowe porównanie to0
==0
, czylitrue
.Edycja: zapoznaj się z tą sekcją specyfikacji, aby uzyskać szczegółowe informacje na temat tego, jak to działa.
Oto, co się dzieje, zaczynając od zasady nr 1:
Następna zasada, która ma zastosowanie, to # 19:
Rezultatem
ToNumber(false)
jest0
, więc teraz mamy:Ponownie reguła nr 1 mówi nam, aby przejść do kroku nr 14, ale następnym krokiem, który faktycznie ma zastosowanie, jest nr 21:
Wynikiem
ToPrimitive([])
jest pusty ciąg, więc teraz mamy:Ponownie reguła nr 1 mówi nam, aby przejść do kroku nr 14, ale następnym krokiem, który faktycznie ma zastosowanie, jest nr 17:
Rezultatem
ToNumber("")
jest0
, co pozostawia nam:Teraz obie wartości mają ten sam typ, więc kroki są kontynuowane od nr 1 do nr 7, co oznacza:
Więc wracamy
true
.W skrócie:
źródło
[] == 0
jest prawdą. Rozumiem, jak to się dzieje na podstawie twojego wyjaśnienia specyfikacji, ale z logicznego punktu widzenia wygląda to na dziwne zachowanie językowe.Aby uzupełnić odpowiedź Wayne'a i spróbować wyjaśnić, dlaczego
ToPrimitive([])
powraca""
, warto rozważyć dwa możliwe typy odpowiedzi na pytanie „dlaczego”. Pierwszy typ odpowiedzi brzmi: „ponieważ specyfikacja mówi, że tak będzie działał JavaScript”. W specyfikacji ES5, sekcja 9.1 , która opisuje wynik ToPrimitive jako wartość domyślną dla obiektu:Sekcja 8.12.8 opisuje tę
[[DefaultValue]]
metodę. Ta metoda przyjmuje „podpowiedź” jako argument, a podpowiedź może być ciągiem lub liczbą. Aby uprościć sprawę, rezygnując z niektórych szczegółów, jeśli podpowiedź to String, to[[DefaultValue]]
zwraca wartośćtoString()
if, jeśli istnieje i zwraca pierwotną wartość, a w przeciwnym razie zwraca wartośćvalueOf()
. Jeśli wskazówką jest Liczba, priorytetytoString()
ivalueOf()
są odwrócone, tak więcvalueOf()
wywoływana jest pierwsza, a jej wartość zwracana, jeśli jest prymitywna. Tak więc, czy[[DefaultValue]]
zwraca wyniktoString()
lubvalueOf()
zależy od określonego PreferredType dla obiektu i czy te funkcje zwracają wartości prymitywne.Domyślna
valueOf()
metoda Object po prostu zwraca sam obiekt, co oznacza, że jeśli klasa nie zastąpi metody domyślnej,valueOf()
po prostu zwraca sam Obiekt. Tak jest w przypadkuArray
.[].valueOf()
zwraca[]
sam obiekt . PonieważArray
obiekt nie jest prymitywny,[[DefaultValue]]
podpowiedź nie ma znaczenia: wartością zwracaną dla tablicy będzie wartośćtoString()
.Cytując JavaScript Davida Flanagana : The Definitive Guide , który, nawiasem mówiąc, jest świetną książką, która powinna być pierwszym miejscem, w którym każdy powinien uzyskać odpowiedzi na tego rodzaju pytania:
Drugi rodzaj odpowiedzi na pytanie „dlaczego”, inny niż „ponieważ specyfikacja mówi”, daje pewne wyjaśnienie, dlaczego zachowanie ma sens z punktu widzenia projektu. W tej kwestii mogę tylko spekulować. Po pierwsze, jak przekonwertować tablicę na liczbę? Jedyną sensowną możliwością, jaką mogę wymyślić, byłoby przekonwertowanie pustej tablicy na 0, a dowolnej niepustej tablicy na 1. Ale jak ujawniła odpowiedź Wayne'a, pusta tablica zostanie przekonwertowana na 0 dla wielu typów porównań. Poza tym trudno jest wymyślić sensowną prymitywną wartość zwracaną dla Array.valueOf (). Można więc argumentować, że sensowniej jest mieć
Array.valueOf()
wartość domyślną i zwrócić samą tablicę, co prowadzitoString()
do wyniku używanego przez ToPrimitive. Bardziej sensowne jest przekonwertowanie tablicy na ciąg znaków niż na liczbę.Ponadto, jak sugeruje cytat Flanagana, ta decyzja projektowa umożliwia pewne rodzaje korzystnych zachowań. Na przykład:
To zachowanie pozwala porównać tablicę jednoelementową z liczbami i uzyskać oczekiwany wynik.
źródło
źródło
W if (arr) zawsze jest oceniane (ToBoolean) na true, jeśli arr jest obiektem, ponieważ wszystkie obiekty w JavaScript są prawdziwe . (null nie jest przedmiotem!)
[] == false
jest oceniany w podejściu iteracyjnym. Na początku, jeśli jedna strona==
jest prymitywna, a druga to obiekt, najpierw konwertuje obiekt na prymityw, a następnie konwertuje obie strony na Liczba, jeśli obie strony nie sąstring
(porównanie ciągów jest stosowane, jeśli obie strony są ciągami). Porównanie jest więc powtarzane jak:[] == false
->'' == false
->0 == 0
->true
.źródło
Przykład:
Dzieje się tak, ponieważ
[]
jest pustyArray
obiekt →ToPrimitive([])
→ „” →ToNumber("")
→0
ToNumber(false)
→ 0źródło
Tablica z elementami (niezależnie od tego, czy 0, fałsz, czy inna pusta tablica) zawsze decyduje się na
true
użycie Abstrakcyjnego porównania równości==
.Ale używając porównania ścisłej równości
===
, próbujesz ocenić zawartość zmiennej, a także jej typ danych, dlatego:źródło
Możesz opróżnić tablicę JavaScript, odwołując się do nowej tablicy, używając
list = []
lub usuwając elementy aktualnie przywoływanej tablicylist.length = 0
.Źródło: JavaScript Empty Array
źródło
Żadne z powyższych nie pomogło mi, gdy próbowałem użyć wtyczki mapowania knockout.js, być może ponieważ „pusta tablica” nie jest tak naprawdę pusta.
Skończyło się na tym:
data-bind="if: arr().length"
co zrobiło.Jest to specyficzne dla nokautu, a nie pytania OP, ale może pomoże komuś innemu przeglądać tutaj w podobnej sytuacji.
źródło