In JavaScript, perché "0" è uguale a falso, ma quando testato da "if" non è falso da solo?


232

Quanto segue mostra che "0"è falso in Javascript:

>>> "0" == false
true

>>> false == "0"
true

Quindi perché stampa quanto segue "ha"?

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

47
"0"è una stringa e poiché non è vuota, viene valutata come vera.
Aereo digitale

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

3
Scopri la verità dell'articolo di Angus Croll in javascript. javascriptweblog.wordpress.com/2011/02/07/…
timrwood,

8
'0'==falsema '0' non è un valore di falso (sì, Javascript può essere strano)
Linsey,

5
@Linsey: l'intera faccenda della "falsità" e della "verità" è sempre stata intesa a spiegare come i valori vengono convertiti in valori booleani. Quando si confrontano due valori con ==, non vengono mai convertiti in valori booleani, quindi non si applica. (Le regole per la conversione sembrano favorire la conversione in numeri.)
millimoose

Risposte:


251

Il motivo è che quando lo fai esplicitamente "0" == false, entrambi i lati vengono convertiti in numeri e quindi viene eseguito il confronto.

Quando lo fai if ("0") console.log("ha"):, il valore della stringa è in fase di test. Qualsiasi stringa non vuota lo è true, mentre una stringa vuota lo è false.

Uguale (==)

Se i due operandi non sono dello stesso tipo , JavaScript converte gli operandi quindi applica un confronto rigoroso. Se uno degli operandi è un numero o un valore booleano , gli operandi vengono convertiti in numeri se possibile; altrimenti se uno degli operandi è una stringa , l'altro operando viene convertito in una stringa se possibile. Se entrambi gli operandi sono oggetti , JavaScript confronta i riferimenti interni uguali quando gli operandi si riferiscono allo stesso oggetto in memoria.

(Da operatori di confronto nella rete di sviluppatori Mozilla)


348

Tabelle che mostrano il problema:

verità se affermazione

e == confronti veritieri di tutti i tipi di oggetti in javascript

Morale della storia usa === uguaglianza rigorosa che mostra sanità mentale

credito di generazione della tabella: https://github.com/dorey/JavaScript-Equality-Table


2
Ha molto più senso con un altro ordine di valori gist.github.com/kirilloid/8165660
Kirilloid,

3
D'ora in poi, se qualcuno dice che non usa mai operatori di confronto rigorosi, lo affronterò con queste tabelle e lo farò piangere. Non sono ancora sicuro di capire il concetto di NaNperò. Voglio dire, typeof NaN // numberma NaN === NaN // false, hmm ...
Justus Romijn,

4
Un mio amico ha reso f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - gli stessi grafici di cui sopra, ma un po 'più facili da leggere.
Lucy Bain,

@JustusRomijn ci sono più valori da rappresentare NaN, quindi quando si confrontano 2 NaN, hanno valori diversi (immagino). Leggi la prima citazione qui .
cychoi,

4
Queste tabelle hanno un errore. Né =====operatore per la [], {}, [[]], [0]e [1]valori non restituiscono true. Intendo [] == []e [] === []anche falso.
Herbertusz,

38

È secondo le specifiche.

12.5 L'istruzione if 
.....

2. Se ToBoolean (GetValue (exprRef)) è true, allora 
un. Restituisce il risultato della valutazione della prima istruzione.
3. Altrimenti, 
....

ToBoolean, secondo le specifiche, è

L'operazione astratta ToBoolean converte il suo argomento in un valore di tipo Booleano secondo la Tabella 11:

E quella tabella dice questo sulle stringhe:

inserisci qui la descrizione dell'immagine

Il risultato è falso se l'argomento è la stringa vuota (la sua lunghezza è zero); altrimenti il ​​risultato è vero

Ora, per spiegare perché "0" == falsedovresti leggere l'operatore di uguaglianza, che afferma che ottiene il suo valore dall'operazione astratta GetValue(lref)corrisponde allo stesso per il lato destro.

Che descrive questa parte rilevante come:

se IsPropertyReference (V), quindi 
un. Se HasPrimitiveBase (V) è falso, allora lascia che sia il metodo interno [[Get]] di base, altrimenti lascia che get
essere lo speciale metodo interno [[Get]] definito di seguito. 
b. Restituisce il risultato della chiamata del metodo get interno utilizzando base come suo valore e passaggio
GetReferencedName (V) per l'argomento

O in altre parole, una stringa ha una base primitiva, che richiama il metodo get interno e finisce per sembrare falsa.

Se si desidera valutare le cose utilizzando l'operazione GetValue, utilizzare ==se si desidera valutare utilizzando ToBoolean, ===(noto anche come operatore di parità "rigoroso")


"a string has a primitive base, which calls back the internal get method and ends up looking false"È vero per tutte le stringhe?
Aziz Punjani,

@Interstellar_Coder Section 8.12.3: [[Get]] (P)descrive come funziona. È vero solo per i casi in cui la stringa è 0, poiché alla fine risulta un mucchio di altre chiamate interne GetOwnPropertyche vedono che "qualunque" sia una proprietà di dati, che quindi restituisce completamente quel valore. Questo è il motivo per cui "0" è falso e "blah" è vero. Guarda alcuni dei video di Douglas Crockford sul teatro degli sviluppatori di Yahoo, descrive la "verità" in JavaScript un po 'meno complessa di me. Se capisci cosa significa "verità" e "falsità", capirai subito la risposta di Bobince.
Incognito,

1
Dove posso trovare le specifiche?
user985366

12

È PHP in cui la stringa "0"è falsy (false-when-used-in-boolean-context). In JavaScript, tutte le stringhe non vuote sono veritiere.

Il trucco è che ==nei confronti di un booleano non viene valutato in un contesto booleano, viene convertito in numero e nel caso di stringhe eseguite analizzando come decimale. Quindi ottieni Number 0invece della verità booleana true.

Questo è un po 'povero di design del linguaggio ed è uno dei motivi per cui cerchiamo di non usare lo sfortunato ==operatore. Usa ===invece.


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

Le virgolette intorno alla 0rendono una stringa, che viene valutata come vera.

Rimuovi le virgolette e dovrebbe funzionare.

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

corretto, non su come "farlo funzionare" ma la domanda è più simile a "perché si è comportato in quel modo?"
polarità


1

L'espressione "if" verifica la veridicità, mentre il doppio eguaglia test per l'equivalenza indipendente dal tipo. Una stringa è sempre vera, come altri hanno sottolineato qui. Se il doppio uguale testasse la veridicità di entrambi i suoi operandi e quindi confrontasse i risultati, otterresti il ​​risultato che stavi assumendo intuitivamente, cioè ("0" == true) === true. Come dice Doug Crockford nel suo eccellente JavaScript: le parti buone ", le regole secondo cui [== costringe i tipi dei suoi operandi] sono complicate e non memorabili .... La mancanza di transitività è allarmante". Basti dire che uno degli operandi è forzato per corrispondere all'altro e che "0" finisce per essere interpretato come zero numerico,


1

== L' operatore di uguaglianza valuta gli argomenti dopo averli convertiti in numeri. Quindi la stringa zero "0" viene convertita in tipo di dati Numero e il valore booleano falso viene convertito in Numero 0. Quindi

"0" == false // true

Lo stesso vale per `

false == "0" //true

=== Il rigoroso controllo dell'uguaglianza valuta gli argomenti con il tipo di dati originale

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

Lo stesso vale per

false === "0" // false

Nel

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

La stringa "0" non viene confrontata con nessun argomento e la stringa è un valore vero fino a quando o se non viene confrontata con alcun argomento. È esattamente come

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

Ma

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

`


1

Questo perché JavaScript utilizza la coercizione dei tipi nei contesti booleani e nel codice

if ("0") 

sarà costretto a diventare vero in contesti booleani.

Ci sono altri valori di verità in Javascript che saranno costretti a veri in contesti booleani e quindi eseguiranno i blocchi 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)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.