Douglas Crockford a écrit dans JavaScript, les bonnes parties :
JavaScript a deux ensembles d'opérateurs d'égalité:
===
et!==
, et leurs jumeaux maléfiques==
et!=
. Les bons fonctionnent comme vous le souhaiteriez. Si les deux opérandes sont du même type et ont la même valeur, alors===
producttrue
et!==
productfalse
. Les jumeaux maléfiques font ce qui est juste quand les opérandes sont du même type, mais s’ils sont de types différents, ils tentent de contraindre les valeurs. Les règles selon lesquelles ils le font sont compliquées et immuables. Voici quelques cas intéressants:'' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' \t\r\n ' == 0 // true
Le manque de transitivité est alarmant. Mon conseil est de ne jamais utiliser les jumeaux maléfiques. Au lieu de cela, utilisez toujours
===
et!==
. Toutes les comparaisons que nous venons de montrer produisentfalse
avec l'===
opérateur.
Compte tenu de cette observation sans équivoque, y a-t-il un moment où l'utilisation ==
pourrait réellement être appropriée?
la source
==
par défaut,===
se démarque et me laisse savoir que quelque chose d'important se passe.Réponses:
Je vais faire un argument pour
==
Douglas Crockford, que vous avez cité, est connu pour ses opinions nombreuses et souvent très utiles. Bien que je sois avec Crockford dans ce cas particulier, il convient de mentionner que ce n'est pas la seule opinion. Il y en a d'autres, comme le créateur de langue Brendan Eich, qui ne voient pas le gros problème avec
==
. L'argument va un peu comme ceci:JavaScript est un langage typé comportementalement. Les choses sont traitées en fonction de ce qu'elles peuvent faire et non de leur type réel. C'est pourquoi vous pouvez appeler la
.map
méthode d' un tableau sur une liste de noeuds ou sur un jeu de sélection jQuery. C'est aussi pourquoi vous pouvez faire3 - "5"
quelque chose de significatif et le récupérer - parce que "5" peut agir comme un nombre.Lorsque vous effectuez une
==
égalité, vous comparez le contenu d'une variable plutôt que son type . Voici quelques cas où cela est utile:.value
d'un élément d'entrée dans le DOM? Aucun problème! Vous n'avez pas à commencer à le diffuser ni à vous soucier de son type - vous pouvez==
tout de suite numéroter et obtenir quelque chose de significatif.== null
faire puisque le comportementnull
représente qu'il n'y a rien là-bas et qu'undefined n'y a rien non plus.==
argument, il traitera les cas où l'utilisateur n'a rien entré ou juste un espace pour vous, ce qui est probablement ce dont vous avez besoin.Regardons les exemples de Crockford et expliquons-les de manière comportementale:
Fondamentalement, il
==
est conçu pour fonctionner en fonction du comportement des primitives en JavaScript et non en fonction de ce qu'elles sont . Bien que je ne sois pas personnellement d’accord avec ce point de vue, il est tout à fait justifié de le faire - en particulier si vous prenez ce paradigme de traiter les types en fonction du comportement dans l’ensemble du langage.* Certains préfèreront peut-être le nom de typage structural qui est plus courant mais il y a une différence - ne pas vraiment intéressé à discuter de la différence ici.
la source
==
c’est qu’aucune de ses comparaisons n’est utile , c’est que les règles sont impossibles à mémoriser, de sorte que vous êtes presque certain de faire des erreurs. Par exemple: "Besoin de vérifier si vous avez obtenu une entrée significative de la part d'un utilisateur?", Mais "0" est une entrée significative et'0'==false
vraie. Si vous aviez utilisé===
vous auriez dû explicitement penser à cela et vous n'auriez pas commis l'erreur.3 - "5"
exemple soulève un bon point en soi: même si vous utilisez exclusivement à des fins===
de comparaison, c'est simplement ainsi que les variables fonctionnent en Javascript. Il n'y a aucun moyen d'y échapper complètement.==
dans mon propre code, je trouve que c'est un anti-motif et je suis tout à fait d'accord pour dire que l'algorithme d'égalité abstraite est difficile à retenir. Ce que je fais ici, c'est l'argument avancé par les gens.JQuery utilise la construction
largement, comme raccourci pour le code équivalent:
C’est une conséquence de la spécification de langage ECMAScript, § 11.9.3, Algorithme de comparaison d’égalité abstraite , qui indique notamment que
et
Cette technique particulière est assez courante pour que JSHint ait un drapeau spécialement conçu à cet effet.
la source
== null or undefined
est le seul endroit où je n'utilise pas===
ou!==
==
utiliser par défaut et ne l’utilise que===
dans les cas où cela est nécessaire: github.com/madrobby/zepto/blob/master/src/event.js__proto__
et son forçage presque à lui seul dans la spécification du langage pour éviter de casser des sites Web mobiles.Vérifier les valeurs pour
null
ouundefined
est une chose, comme cela a été expliqué abondamment.Il y a autre chose, où
==
brille:Vous pouvez définir une comparaison de la
>=
manière suivante (les gens partent généralement de>
mais je trouve cela plus élégant):a > b
<=>a >= b && !(b >= a)
a == b
<=>a >= b && b >= a
a < b
eta <= b
sont laissés comme un exercice au lecteur.Comme nous le savons, en JavaScript
"3" >= 3
et à"3" <= 3
partir duquel vous obtenez3 == "3"
. Vous pouvez faire remarquer que c’est une idée horrible de permettre la comparaison des chaînes et des nombres en analysant la chaîne. Mais étant donné que c'est ainsi que cela fonctionne,==
c'est absolument la bonne façon de mettre en œuvre cet opérateur de relation.Le point positif
==
est donc que cela correspond à toutes les autres relations. En d'autres termes, si vous écrivez ceci:Vous utilisez
==
déjà implicitement .Passons maintenant à la question assez connexe de: Était-ce un mauvais choix d’implémenter la comparaison des nombres et des chaînes de la façon dont elle est mise en œuvre? Vu isolément, cela semble une chose plutôt stupide à faire. Mais dans le contexte d’autres parties de JavaScript et des DOM, c’est relativement pragmatique, étant donné que:
Object
carte clairsemée des valeurs aux valeurs)input[type=number]
)Pour de nombreuses raisons, il était logique de faire en sorte que les chaînes se comportent comme des nombres lorsque cela est nécessaire. Et en supposant que la comparaison de chaînes et la concaténation de chaînes aient des opérateurs différents (par exemple,
::
pour la concation et une méthode de comparaison (où vous pouvez utiliser toutes sortes de paramètres concernant la sensibilité à la casse ou non)), cela serait en réalité moins compliqué. Mais cette surcharge d’opérateur est probablement en fait d’où vient le "Java" dans "JavaScript";)la source
>=
n'est pas vraiment transitif. Il est tout à fait possible dans JS que nia > b
nia < b
nib == a
(par exemple:)NaN
.+
n'est pas vraiment commutatif, parce queNaN + 5 == NaN + 5
ça ne tient pas. Le fait est que>=
fonctionne avec des valeurs numériques pour lesquelles==
fonctionne de manière cohérente. Il ne devrait pas être surprenant que "pas un nombre" soit par sa nature même pas un nombre-ish;)==
est compatible avec le comportement médiocre de>=
? Super, maintenant j'aurais aimé qu'il y ait un>==
...>=
est plutôt cohérent avec le reste des API langage / standard. Dans sa totalité, JavaScript réussit à être plus que la somme de ses parties bizarres. Si vous voulez un>==
, voudriez-vous aussi un strict+
? En pratique, beaucoup de ces décisions facilitent beaucoup de choses. Donc, je ne me précipiterais pas pour les juger pauvres.>=
est significatif, l'==
est tout autant - c'est tout. Personne ne dit que vous devriez comparer[[]]
avecfalse
. Dans des langages comme C, le résultat de ce niveau de non-sens est un comportement indéfini. Traite-le simplement de la même façon: ne le fais pas. Et tout ira bien. De plus, vous n'aurez pas besoin de vous souvenir de règles magiques. Et puis c'est en fait plutôt simple.En tant que mathématicien professionnel, je vois dans l'opérateur de similarité de Javscript
==
(également appelé "comparaison abstraite", "égalité lâche" ) une tentative de construction d'une relation d'équivalence entre entités, ce qui inclut les fonctions réflexive , symétrique et transitive . Malheureusement, deux de ces trois propriétés fondamentales échouent:==
n'est pas réflexif :A == A
peut être faux, par exemple==
n'est pas transitif :A == B
etB == C
ensemble n'impliquent pasA == C
, par exempleSeule la propriété symétrique survit:
A == B
impliqueB == A
, quelle violation est probablement impensable dans tous les cas et conduirait à une rébellion sérieuse;)Pourquoi les relations d'équivalence sont-elles importantes?
Parce que c’est le type de relation le plus important et le plus répandu, étayé par de nombreux exemples et applications. L'application la plus importante est la décomposition d'entités en classes d'équivalence , ce qui est en soi un moyen très pratique et intuitif de comprendre les relations. Et le fait de ne pas être l’équivalence entraîne l’absence de classes d’équivalence, ce qui entraîne à son tour le manque d’intuitivité et de complexité inutile qui est bien connu.
Pourquoi est-ce une si terrible idée d'écrire
==
pour une relation de non-équivalence?Parce que cela rompt notre familiarité et notre intuition, car toute relation intéressante de similarité, d’égalité, de congruence, d’isomorphisme, d’identité, etc. est une équivalence.
Conversion de type
Au lieu de s’appuyer sur une équivalence intuitive, JavaScript introduit la conversion de type:
Mais comment définit-on la conversion de type? Via un ensemble de règles compliquées à de nombreuses exceptions?
Tentative de construction d'une relation d'équivalence
Booléens Clairement
true
etfalse
ne sont pas identiques et devraient être dans des classes différentes.Nombres. Heureusement, l'égalité des nombres est déjà bien définie, dans laquelle deux nombres différents ne sont jamais dans la même classe d'équivalence. En mathématiques, c'est. En JavaScript, la notion de nombre est quelque peu déformée via la présence du plus exotique
-0
,Infinity
et-Infinity
. Notre intuition mathématique dicte que0
et-0
devrait être dans la même classe (en fait l'-0 === 0
esttrue
), alors que chaque infini est une classe séparée.Nombres et Booléens. Étant donné les classes de nombres, où plaçons-nous les booléens?
false
devient semblable à0
, alors quetrue
devient similaire1
mais pas un autre nombre:Y at-il une logique ici pour mettre en
true
place1
? Certes,1
est distingué, mais tel est le cas-1
. Je ne vois personnellement aucune raison de convertirtrue
à1
.Et ça devient encore pire:
Ainsi
true
est en effet converti dans1
tous les nombres! Est-ce logique? Est-ce intuitif? La réponse est laissée comme exercice;)Mais qu'en est-il de ceci:
Le seul booléen
x
à l'x && true
êtretrue
estx = true
. Ce qui prouve que les deux1
et2
(et tout autre nombre que0
) se convertissent entrue
! Cela montre que notre conversion échoue avec une autre propriété importante - la bijection . Cela signifie que deux entités différentes peuvent se convertir en une seule. Ce qui, en soi, ne doit pas être un gros problème. Le gros problème se pose lorsque nous utilisons cette conversion pour décrire une relation de "similitude" ou "d'égalité lâche" de ce que nous voulons l'appeler. Mais une chose est claire: il ne s'agira pas d'une relation d'équivalence ni d'une description intuitive via des classes d'équivalence.Mais pouvons-nous faire mieux?
Au moins mathématiquement - certainement oui! Une simple relation d'équivalence entre les booléens et les nombres pourrait être construite avec
false
et appartenant0
à la même classe. Ainsifalse == 0
serait la seule égalité lâche non-triviale.Qu'en est-il des chaînes?
Nous pouvons couper les chaînes des espaces au début et à la fin pour les convertir en nombres, nous pouvons également ignorer les zéros au début:
Nous obtenons donc une règle simple pour une chaîne - découpez les espaces et les zéros devant. Soit nous obtenons un nombre ou une chaîne vide, auquel cas nous convertissons ce nombre ou ce chiffre à zéro. Ou nous n'obtenons pas de nombre, auquel cas nous ne convertissons pas et n'obtenons donc aucune nouvelle relation.
De cette façon, nous pourrions obtenir une relation d’équivalence parfaite sur l’ensemble des booléens, des nombres et des chaînes! Sauf que ... Les designers JavaScript ont évidemment un autre avis:
Ainsi, les deux chaînes vers lesquelles les deux se convertissent
0
sont soudainement non similaires! Pourquoi ou pourquoi Selon la règle, les chaînes sont vaguement égales précisément lorsqu'elles sont strictement égales! Non seulement cette règle casse la transitivité comme on le voit, mais elle est également redondante! Quel est l'intérêt de créer un autre opérateur==
pour le rendre strictement identique à l'autre===
?Conclusion
L’opérateur d’égalité lâche
==
aurait pu être très utile s’il respectait certaines lois mathématiques fondamentales. Mais comme ce n'est malheureusement pas le cas, son utilité en souffre.la source
NaN
? De plus, à moins qu'un format de nombre spécifique ne soit imposé pour la comparaison avec des chaînes, il faut obtenir une comparaison de chaîne non intuitive ou une non-transitivité.NaN
agit comme un mauvais citoyen :-). La transivité peut et doit être confirmée pour toute comparaison d’équivalence, intuitive ou non.Oui, j'ai rencontré un cas d'utilisation, en particulier lorsque vous comparez une clé avec une valeur numérique:
Je pense qu'il est beaucoup plus naturel de faire la comparaison comme
key == some_number
plutôt que commeNumber(key) === some_number
ou commekey === String(some_number)
.la source
J'ai rencontré une application très utile aujourd'hui. Si vous souhaitez comparer des nombres complétés, comme
01
avec des entiers normaux,==
fonctionne parfaitement. Par exemple:Cela vous évite de supprimer le 0 et de convertir en entier.
la source
'04'-0 === 4
, ou peutparseInt('04', 10) === 4
+'01' === 1
'011' == 011 // false
en mode non strict et SyntaxError en mode strict. :)Je sais que c'est une réponse tardive, mais il semble y avoir une confusion possible entre
null
etundefined
, qui à mon humble avis est ce qui fait le==
mal, plus encore que le manque de transitivité, ce qui est déjà assez grave. Considérer:Qu'est-ce que cela signifie?
p1
a un superviseur dont le nom est "Alice".p2
a un superviseur dont le nom est "Aucun".p3
explicitement, sans équivoque, n'a pas de superviseur .p4
peut ou peut avoir un superviseur. Nous ne savons pas, nous ne nous en soucions pas, nous ne sommes pas censés savoir (problème de confidentialité?), Ce n'est pas notre affaire.Lorsque vous utilisez,
==
vous confondeznull
etundefined
ce qui est totalement inapproprié. Les deux termes signifient des choses complètement différentes! Dire que je n'ai pas de superviseur simplement parce que j'ai refusé de vous dire qui est mon superviseur est faux!Je crois comprendre que certains programmeurs ne se soucient pas de cette différence entre
null
etundefined
ou choisissent d’utiliser ces termes différemment. Et si votre monde ne pas utilisernull
etundefined
correctement, ou si vous souhaitez donner à votre propre interprétation de ces termes, ainsi que ce soit. Je ne pense pas que ce soit une bonne idée cependant.En passant, je n'ai aucun problème avec
null
et lesundefined
deux sont faussaires! C'est parfaitement correct de direet ensuite
null
,undefined
le code qui traite le superviseur sera ignoré. C'est exact, car nous ne savons pas ou n'avons pas de superviseur. Tout bon. Mais les deux situations ne sont pas égales . C'est pourquoi==
est faux. Encore une fois, les choses peuvent être faussées et utilisées dans le sens de la frappe de canard, ce qui est excellent pour les langages dynamiques. C'est JavaScript, Pythonic, Rubyish, etc., mais ces choses ne sont PAS égales.Et ne me lancez pas sur la non-transitivité:
"0x16" == 10
,10 == "10"
mais pas"10" == "0x16"
. Oui, JavaScript est faiblement typé. Oui, c'est coercitif. Mais la coercition ne devrait jamais, jamais, s'appliquer à l'égalité.À propos, Crockford a des opinions bien arrêtées. Mais tu sais quoi? Il a raison ici!
FWIW Je comprends qu’il existe et que j’ai personnellement été confronté à des situations
==
pratiques. C'est comme prendre une chaîne de caractères pour les nombres et, par exemple, comparer à 0. Cependant, c'est du piratage. Vous avez la commodité comme compromis pour un modèle imprécis du monde.TL; DR: la fausseté est un très bon concept. Cela ne devrait pas aller jusqu'à l'égalité.
la source
p5
... La seule situation danstypeof(p5.supervisor) === typeof(undefined)
laquelle le superviseur n’existe même pas en tant que concept: D