Les tableaux vides sont vrais mais ils sont également égaux à faux.
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??");
Je suppose que cela est dû à la conversion implicite opérée par l'opérateur d'égalité.
Quelqu'un peut-il expliquer ce qui se passe dans les coulisses?
javascript
Patonza
la source
la source
arr == true
n'évalue pas vrai ;-)===
. Ensuite, si vous voulez tester le vide d'un tableau, utilisezarr === []
arr === []
, car cela retournera TOUJOURS faux, car le côté droit instancie un nouveau tableau, et la variable de gauche ne peut pas faire référence à quelque chose que vous venez de créer. Le test du vide doit être effectué en levant les yeuxarr.length === 0
.Réponses:
Vous testez différentes choses ici.
if (arr)
appelé sur l'objet (Array est une instance d'Object dans JS) vérifiera si l'objet est présent et retourne vrai / faux.Lorsque vous appelez,
if (arr == false)
vous comparez les valeurs de cet objet et lafalse
valeur primitive . En interne,arr.toString()
est appelé, qui renvoie une chaîne vide""
.Cela est dû au fait que
toString
les retoursArray.join()
de tableaux sont appelés et que la chaîne vide est l'une des valeurs falsifiées en JavaScript.la source
Boolean([])
revienttrue
?Concernant la ligne:
Peut-être que cela aidera:
Ce qui, je crois, se produit, c'est que le booléen
false
est contraint de le0
comparer à un objet (le côté gauche). L'objet est contraint à une chaîne (la chaîne vide). Ensuite, la chaîne vide est également contrainte en un nombre, à savoir zéro. Et donc la comparaison finale est0
==0
, ce qui esttrue
.Modifier: voir cette section de la spécification pour plus de détails sur la façon dont cela fonctionne.
Voici ce qui se passe, à partir de la règle n ° 1:
La prochaine règle qui s'applique est # 19:
Le résultat de
ToNumber(false)
est0
, nous avons donc maintenant:Encore une fois, la règle n ° 1 nous dit de passer à l'étape n ° 14, mais la prochaine étape qui s'applique réellement est la n ° 21:
Le résultat de
ToPrimitive([])
est la chaîne vide, nous avons donc maintenant:Encore une fois, la règle n ° 1 nous dit de passer à l'étape n ° 14, mais la prochaine étape qui s'applique réellement est la n ° 17:
Le résultat de
ToNumber("")
is0
, qui nous laisse avec:Maintenant, les deux valeurs ont le même type, donc les étapes continuent de # 1 à # 7, qui dit:
Donc, nous revenons
true
.En bref:
la source
[] == 0
c'est vrai. Je comprends comment cela se produit en fonction de votre explication de la spécification, mais cela semble être un comportement de langage étrange d'un point de vue logique.Pour compléter la réponse de Wayne et essayer d'expliquer pourquoi il
ToPrimitive([])
revient""
, il vaut la peine d'envisager deux types de réponses possibles à la question «pourquoi». Le premier type de réponse est: "parce que la spécification indique que c'est ainsi que JavaScript se comportera." Dans la spécification ES5, section 9.1 , qui décrit le résultat de ToPrimitive comme valeur par défaut pour un objet:La section 8.12.8 décrit la
[[DefaultValue]]
méthode. Cette méthode prend un "indice" comme argument, et l'indice peut être soit String soit Number. Pour simplifier la question en supprimant certains détails, si l'indice est String,[[DefaultValue]]
renvoie la valeur detoString()
s'il existe et renvoie une valeur primitive et renvoie sinon la valeur devalueOf()
. Si l'indice est Number, les priorités detoString()
etvalueOf()
sont inversées de sorte que levalueOf()
premier est appelé et sa valeur renvoyée s'il s'agit d'une primitive. Ainsi, si[[DefaultValue]]
renvoie le résultat detoString()
ouvalueOf()
dépend du PreferredType spécifié pour l'objet et si ces fonctions renvoient ou non des valeurs primitives.La
valueOf()
méthode Object par défaut renvoie simplement l'objet lui-même, ce qui signifie qu'à moins qu'une classe ne remplace la méthode par défaut,valueOf()
renvoie simplement l'objet lui-même. C'est le cas pourArray
.[].valueOf()
renvoie l'objet[]
lui-même. Puisqu'unArray
objet n'est pas une primitive, l'[[DefaultValue]]
indice n'est pas pertinent: la valeur de retour pour un tableau sera la valeur detoString()
.Pour citer le JavaScript de David Flanagan : le guide définitif , qui, soit dit en passant, est un superbe livre qui devrait être le premier endroit de chacun pour obtenir des réponses à ces types de questions:
Le deuxième type de réponse à la question «pourquoi», autre que «parce que la spécification dit», explique pourquoi le comportement est logique du point de vue de la conception. Sur cette question, je ne peux que spéculer. Premièrement, comment convertir un tableau en nombre? La seule possibilité raisonnable à laquelle je peux penser serait de convertir un tableau vide en 0 et tout tableau non vide en 1. Mais comme l'a révélé la réponse de Wayne, un tableau vide sera converti en 0 pour de nombreux types de comparaisons de toute façon. Au-delà de cela, il est difficile de penser à une valeur de retour primitive sensible pour Array.valueOf (). On pourrait donc dire qu'il est plus logique d'avoir
Array.valueOf()
la valeur par défaut et de renvoyer le tableau lui-même, cetoString()
qui conduit au résultat utilisé par ToPrimitive. Il est plus logique de convertir un tableau en chaîne plutôt qu'en nombre.De plus, comme l'indique la citation de Flanagan, cette décision de conception permet certains types de comportements bénéfiques. Par exemple:
Ce comportement vous permet de comparer un tableau à un élément aux nombres et d'obtenir le résultat attendu.
la source
la source
Dans if (arr), il est toujours évalué (ToBoolean) à true si arr est un objet car tous les objets en JavaScript sont véridiques . (null n'est pas un objet!)
[] == false
est évalué en approche itérative. Au début, si un côté de==
est primitif et l'autre est objet, il convertit d'abord l'objet en primitif, puis convertit les deux côtés en Nombre si les deux côtés ne le sont passtring
(la comparaison de chaînes est utilisée si les deux côtés sont des chaînes). La comparaison est donc répétée comme,[] == false
->'' == false
->0 == 0
->true
.la source
Exemple:
Cela arrive parce que
[]
est unArray
objet vide →ToPrimitive([])
→ "" →ToNumber("")
→0
ToNumber(false)
→ 0la source
Un tableau avec des éléments (que ce soit 0, faux ou un autre tableau vide), se résout toujours à
true
utiliser la comparaison d'égalité abstraite==
.Mais en utilisant une comparaison stricte d'égalité
===
, vous essayez d'évaluer le contenu de la variable ainsi que son type de données, c'est pourquoi:la source
Vous pouvez vider un tableau JavaScript en le référençant à un nouveau tableau, en utilisant
list = []
ou en supprimant les éléments du tableau actuellement référencélist.length = 0
.Source: tableau vide JavaScript
la source
Rien de ce qui précède ne m'a aidé, lorsque j'essayais d'utiliser le plugin de cartographie knockout.js, peut-être car un "tableau vide" n'est pas vraiment vide.
J'ai fini par utiliser:
data-bind="if: arr().length"
qui a fait l'affaire.Ceci est spécifique au KO, pas à la question du PO, mais peut-être que cela aidera quelqu'un d'autre à naviguer ici dans une situation similaire.
la source