En JavaScript, pourquoi «0» est-il égal à faux, mais lorsqu'il est testé par «si», il n'est pas faux en soi?

232

Ce qui suit "0"est faux en Javascript:

>>> "0" == false
true

>>> false == "0"
true

Alors, pourquoi le texte suivant s'imprime- "ha"t-il?

>>> if ("0") console.log("ha")
ha
non-polarité
la source
47
"0"est une chaîne, et comme elle n'est pas vide, elle est évaluée à true.
Avion numérique
8
"0" === false [...] false
3
Découvrez la vérité de l'article d'Angus Croll en javascript. javascriptweblog.wordpress.com/2011/02/07/…
timrwood
8
'0'==falsemais '0' n'est pas une valeur de falsey (oui Javascript peut être bizarre)
Linsey
5
@Linsey: L'ensemble de la "fausse" et de la "vérité" n'a jamais été conçu que pour expliquer comment les valeurs sont converties en booléens. Lorsque vous comparez deux valeurs avec ==, elles ne sont jamais converties en booléens, donc cela ne s'applique pas. (Les règles de conversion semblent favoriser la conversion en nombres.)
millimoose

Réponses:

251

La raison en est que lorsque vous le faites explicitement "0" == false, les deux côtés sont convertis en nombres, puis la comparaison est effectuée.

Lorsque vous effectuez if ("0") console.log("ha"):, la valeur de chaîne est testée. Toute chaîne non vide l'est true, tandis qu'une chaîne vide l'est false.

Égal (==)

Si les deux opérandes ne sont pas du même type , JavaScript convertit les opérandes puis applique une comparaison stricte. Si l'un des opérandes est un nombre ou un booléen , les opérandes sont convertis en nombres si possible; sinon si l'un des opérandes est une chaîne , l'autre opérande est converti en chaîne si possible. Si les deux opérandes sont des objets , JavaScript compare les références internes qui sont égales lorsque les opérandes font référence au même objet en mémoire.

( Des opérateurs de comparaison dans Mozilla Developer Network)

jdi
la source
348

Tableaux affichant le problème:

véridique si déclaration

et == comparaisons véridiques de tous les types d'objets en javascript

Morale de l'utilisation de l'histoire === égalité stricte affichant la raison

crédit de génération de table: https://github.com/dorey/JavaScript-Equality-Table

Joe
la source
2
Cela a beaucoup plus de sens avec un autre ordre de valeurs gist.github.com/kirilloid/8165660
kirilloid
3
Désormais, si quelqu'un dit qu'il n'utilise jamais d'opérateurs de comparaison stricts, je lui ferai face avec ces tableaux et le ferai pleurer. Je ne sais toujours pas si je saisis le concept de NaNbien. Je veux dire, typeof NaN // numbermais NaN === NaN // false, hmm ...
Justus Romijn
4
Un de mes amis a créé f.cl.ly/items/3b0q1n0o1m142P1P340P/javascript_equality.html - les mêmes graphiques que ci-dessus, mais un peu plus faciles à lire.
Lucy Bain
@JustusRomijn il y a plusieurs valeurs à représenter NaN, donc quand vous comparez 2 NaN, elles sont de valeurs différentes (je suppose). Lisez la première citation ici .
cychoi
4
Ces tableaux ont une erreur. Ni , ==ni ===opérateur pour la [], {}, [[]], [0]et les [1]valeurs n'évaluent pas vrai. Je veux dire [] == []et [] === []aussi faux.
Herbertusz
38

C'est selon les spécifications.

12.5 L'instruction if 
.....

2. Si ToBoolean (GetValue (exprRef)) est vrai, alors 
une. Renvoie le résultat de l'évaluation de la première instruction.
3. Sinon, 
....

ToBoolean, selon la spécification, est

L'opération abstraite ToBoolean convertit son argument en une valeur de type Boolean selon le tableau 11:

Et ce tableau dit ceci à propos des chaînes:

entrez la description de l'image ici

Le résultat est faux si l'argument est la chaîne vide (sa longueur est nulle); sinon le résultat est vrai

Maintenant, pour expliquer pourquoi "0" == falsevous devriez lire l'opérateur d'égalité, qui indique qu'il obtient sa valeur de l'opération abstraite GetValue(lref)correspond de même pour le côté droit.

Qui décrit cette partie pertinente comme:

si IsPropertyReference (V), alors 
une. Si HasPrimitiveBase (V) est faux, alors get sera la méthode interne [[Get]] de base, sinon laissez get
être la méthode interne [[Get]] spéciale définie ci-dessous. 
b. Renvoie le résultat de l'appel de la méthode interne get en utilisant la base comme sa valeur this et en passant
GetReferencedName (V) pour l'argument

Ou en d'autres termes, une chaîne a une base primitive, qui rappelle la méthode interne get et finit par sembler fausse.

Si vous souhaitez évaluer des choses à l'aide de l'opération GetValue ==, si vous souhaitez évaluer à l'aide de ToBoolean, utilisez ===(également appelé opérateur d'égalité "strict")

Incognito
la source
"a string has a primitive base, which calls back the internal get method and ends up looking false"Est-ce vrai pour toutes les chaînes?
aziz punjani
@Interstellar_Coder Section 8.12.3: [[Get]] (P)décrit comment cela fonctionne. Ce n'est vrai que pour les cas où la chaîne est 0, car il fait un tas d'autres appels internes qui aboutissent finalement à GetOwnPropertyce que "quoi que ce soit" est une propriété de données, qui retourne ensuite complètement cette valeur. C'est pourquoi "0" est faux et "bla" est vrai. Découvrez quelques-unes des vidéos de Douglas Crockford sur Yahoo Developer Theatre, il décrit la "vérité" en JavaScript un peu moins complexe que moi. Si vous comprenez ce que signifie «véridique» et «fausse», vous comprendrez immédiatement la réponse de Bobince.
Incognito
1
Où puis-je trouver la spécification?
user985366
12

C'est PHP où la chaîne "0"est fausse (false-when-used-in-boolean-context). En JavaScript, toutes les chaînes non vides sont véridiques.

L'astuce est que ==contre un booléen n'évalue pas dans un contexte booléen, il se convertit en nombre, et dans le cas des chaînes, cela se fait en analysant en décimal. Vous obtenez donc Number 0au lieu de la vérité booléenne true.

Il s'agit d'une conception de langage vraiment médiocre et c'est l'une des raisons pour lesquelles nous essayons de ne pas utiliser l' ==opérateur malheureux . Utilisez ===plutôt.

bobince
la source
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.
Thava
la source
4

Vos guillemets autour de la 0font une chaîne, qui est évaluée comme vraie.

Supprimez les guillemets et cela devrait fonctionner.

if (0) console.log("ha") 
Jason Gennaro
la source
correct, pas sur la façon de "faire fonctionner", mais la question est plus comme, "pourquoi il s'est comporté de cette façon?"
non
1

L'expression "si" teste la véracité, tandis que la double égalité teste l'équivalence indépendante du type. Une chaîne est toujours véridique, comme d'autres l'ont souligné ici. Si le double égal testait la véracité de ses deux opérandes et comparait ensuite les résultats, alors vous obtiendriez le résultat que vous supposiez intuitivement, c'est-à-dire ("0" == true) === true. Comme le dit Doug Crockford dans son excellent JavaScript: les bonnes parties , "les règles par lesquelles [== contraint les types de ses opérandes] sont compliquées et immémoriales ... Le manque de transitivité est alarmant". Il suffit de dire que l'un des opérandes est soumis à une contrainte de type pour correspondre à l'autre, et que "0" finit par être interprété comme un zéro numérique,

Jollymorphic
la source
1

== L'opérateur d'égalité évalue les arguments après les avoir convertis en nombres. Ainsi, la chaîne zéro "0" est convertie en type de données Number et la valeur booléenne false est convertie en Number 0. Donc

"0" == false // true

Il en va de même pour `

false == "0" //true

=== Le contrôle d'égalité strict évalue les arguments avec le type de données d'origine

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

Il en va de même pour

false === "0" // false

Dans

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

La chaîne «0» ne se compare à aucun argument et la chaîne est une valeur vraie jusqu'à ce qu'elle soit comparée à un argument ou à moins qu'elle ne soit comparée. C'est exactement comme

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

Mais

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

"

Vishnu K. Panicker
la source
1

En effet, JavaScript utilise la contrainte de type dans les contextes booléens et votre code

if ("0") 

sera contraint à true dans les contextes booléens.

Il existe d'autres valeurs véridiques dans Javascript qui seront forcées à true dans des contextes booléens, et ainsi exécuter le bloc if sont: -

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)
Sachin
la source