Dlaczego w JavaScripcie „0” jest równe false, ale gdy jest testowane przez „jeśli”, to samo w sobie nie jest fałszem?


232

Poniższe informacje pokazują, że "0"w Javascript jest fałszem:

>>> "0" == false
true

>>> false == "0"
true

Dlaczego więc drukuje następujący "ha"?

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

47
"0"jest ciągiem, a ponieważ nie jest pusty, jest sprawdzany jako prawdziwy.
Digital Plane

8
"0" === false [...] false

3
Sprawdź prawdę w artykule Angusa Crolla w javascript. javascriptweblog.wordpress.com/2011/02/07/…
timrwood 30.09.11

8
'0'==falseale „0” nie jest wartością falsey (tak JavaScript może być dziwny)
Linsey

5
@Linsey: Cała ta „falsja” i „prawda” miała na celu wyłącznie wyjaśnienie, w jaki sposób wartości są przekształcane w wartości logiczne. Gdy porównasz dwie wartości ==, nigdy nie zostaną one przekonwertowane na wartości logiczne, więc nie ma zastosowania. (Reguły konwersji wydają się sprzyjać konwersji na liczby.)
millimoose

Odpowiedzi:


251

Powodem jest to, że gdy to zrobisz "0" == false, obie strony są konwertowane na liczby, a następnie przeprowadzane jest porównanie.

Gdy to zrobisz: if ("0") console.log("ha")wartość ciągu jest testowana. Każdy niepusty ciąg jest true, a pusty ciąg jest false.

Równa (==)

Jeśli dwa operandy nietego samego typu , JavaScript konwertuje operandy, a następnie stosuje ścisłe porównanie. Jeśli jeden z operandów jest liczbą lub wartością logiczną , operandy są przekształcane na liczby, jeśli to możliwe; w przeciwnym razie, jeśli jeden z operandów jest ciągiem , drugi operand jest przekształcany na ciąg, jeśli to możliwe. Jeśli oba operandy są obiektami , JavaScript porównuje odwołania wewnętrzne, które są równe, gdy operandy odnoszą się do tego samego obiektu w pamięci.

(Od operatorów porównania w Mozilla Developer Network)


348

Tabele przedstawiające problem:

prawda, jeśli oświadczenie

i == prawdziwe porównania wszystkich typów obiektów w javascript

Morał z tej historii === ścisła równość wykazująca rozsądek

kredyt na generowanie tabeli: https://github.com/dorey/JavaScript-Equality-Table


2
Ma to o wiele większy sens w przypadku kolejnej wartości: gist.github.com/kirilloid/8165660
kirilloid 28.12.2013

3
Odtąd, jeśli ktoś powie, że nigdy nie używa ścisłych operatorów porównania, stanę przed nim z tymi tabelami i sprawię, że będzie płakał. Nadal nie jestem pewien, czy rozumiem pojęcie NaN. To znaczy, typeof NaN // numberale NaN === NaN // false, hmm ...
Justus Romijn,

4
Mój przyjaciel stworzył f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - te same wykresy jak wyżej, ale trochę łatwiej je odczytać.
Lucy Bain,

@JustusRomijn istnieje wiele wartości do reprezentowania NaN, więc gdy porównujesz 2 NaN, mają one różne wartości (tak myślę). Przeczytaj pierwszy cytat tutaj .
szczegółowooi

4
Te tabele mają błąd. Ani ==ani ===operator dla [], {}, [[]], [0]i [1]wartości nie oceniać true. Mam na myśli, [] == []a [] === []także fałsz.
Herbertusz

38

Jest to zgodne ze specyfikacją.

12.5 Instrukcja if 
.....

2. Jeśli ToBoolean (GetValue (exprRef)) jest prawdziwe, to 
za. Zwraca wynik oceny pierwszej instrukcji.
3. W przeciwnym razie 
…

ToBoolean, zgodnie ze specyfikacją, to

Abstrakcyjna operacja ToBoolean konwertuje swój argument na wartość typu Boolean zgodnie z tabelą 11:

I ta tabela mówi o ciągach:

wprowadź opis zdjęcia tutaj

Wynik jest fałszywy, jeśli argument jest pustym ciągiem (jego długość wynosi zero); w przeciwnym razie wynik jest prawdziwy

Teraz, aby wyjaśnić, dlaczego "0" == falsepowinieneś przeczytać operator równości, który stwierdza, że ​​pobiera swoją wartość z operacji abstrakcyjnej, jest GetValue(lref)taki sam dla prawej strony.

Który opisuje tę istotną część jako:

jeśli IsPropertyReference (V), to 
za. Jeśli HasPrimitiveBase (V) ma wartość false, to niech get będzie [[Get]] wewnętrzną metodą bazową, w przeciwnym razie niech get
być specjalną wewnętrzną metodą [[Get]] zdefiniowaną poniżej. 
b. Zwraca wynik wywołania metody get get przy użyciu wartości base jako tej wartości i przekazania
GetReferencedName (V) dla argumentu

Innymi słowy, łańcuch ma prymitywną podstawę, która wywołuje wewnętrzną metodę get i kończy się na fałszu.

Jeśli chcesz oceniać rzeczy za pomocą operacji GetValue użyj ==, jeśli chcesz oceniać za pomocą ToBoolean, użyj ===(również znany jako „ścisły” operator równości)


"a string has a primitive base, which calls back the internal get method and ends up looking false"Czy to prawda dla wszystkich ciągów?
aziz punjani

@ Interstellar_Coder Section 8.12.3: [[Get]] (P)opisuje, jak to działa. Jest to prawdą tylko w przypadkach, gdy ciąg znaków ma wartość 0, ponieważ wykonuje kilka innych wywołań wewnętrznych, w wyniku GetOwnPropertyktórych widzi, że „cokolwiek” jest właściwością danych, która następnie zwraca tę wartość z powrotem. Dlatego „0” jest fałszem, a „bla” jest prawdą. Sprawdź niektóre z filmów Douglasa Crockforda w teatrze programistów Yahoo, opisuje on w JavaScripcie „prawdomówność” nieco mniej skomplikowany niż ja. Jeśli zrozumiesz, co oznacza „prawda” i „fałsz”, od razu zrozumiesz odpowiedź Bobince'a.
Incognito

1
Gdzie mogę znaleźć specyfikację?
user985366

12

To PHP, w którym ciąg znaków "0"jest fałszem (false-when-used-in-boolean-context). W JavaScript wszystkie niepuste ciągi są zgodne z prawdą.

Sztuka polega na tym, że w ==przypadku wartości logicznej nie jest obliczana w kontekście logicznym, konwertuje się na liczbę, aw przypadku ciągów, które są wykonywane przez parsowanie jako dziesiętne. Więc dostajesz liczbę 0zamiast boolean z prawdomówności true.

To naprawdę kiepski projekt językowy i jest to jeden z powodów, dla których staramy się nie używać niefortunnego ==operatora. Użyj ===zamiast tego.


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.

4

Twoje cudzysłowy 0tworzą ciąg, który jest oceniany jako prawdziwy.

Usuń cytaty i powinno działać.

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

prawda, nie chodzi o to, jak „sprawić, by działało”, ale pytanie brzmi bardziej: „dlaczego tak się zachowało?”
nonpolarity


1

Wyrażenie „if” sprawdza prawdziwość, a testy podwójnej równości dla równoważności niezależnej od typu. Ciąg jest zawsze prawdziwy, jak zauważyli inni tutaj. Gdyby podwójna równość testowała oba argumenty pod kątem prawdziwości, a następnie porównywała wyniki, to uzyskałbyś wynik, który intuicyjnie zakładałeś, tj ("0" == true) === true. Jak mówi Doug Crockford w swoim doskonałym skrypcie JavaScript: dobre części , „zasady, według których [== wymusza typy operandów] są skomplikowane i nie można ich zapamiętywać ... Brak przechodniości jest alarmujący”. Wystarczy powiedzieć, że jeden z operandów jest wymuszony na typ, aby pasował do drugiego, i że „0” kończy się interpretacją jako zero numeryczne,


1

== Operator równości ocenia argumenty po przekonwertowaniu ich na liczby. Zatem ciąg zerowy „0” jest konwertowany na typ danych Liczba, a wartość logiczna „fałsz” jest konwertowana na liczbę 0. Tak

"0" == false // true

To samo dotyczy `

false == "0" //true

=== Ścisła kontrola równości ocenia argumenty z oryginalnym typem danych

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

To samo dotyczy

false === "0" // false

W

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

Łańcuch „0” nie jest porównywany z żadnymi argumentami, a łańcuch jest prawdziwą wartością, dopóki nie zostanie porównany z jakimikolwiek argumentami. To jest dokładnie jak

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

Ale

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

`


1

Wynika to z faktu, że JavaScript używa przymusu typu w kontekstach boolowskich i kodzie

if ("0") 

zostanie wymuszony na true w kontekście boolowskim.

Istnieją inne prawdziwe wartości w Javascript, które zostaną wymuszone na true w kontekstach boolowskich, a zatem wykonają blok if:

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)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.