J'ai dû écrire une routine qui incrémente la valeur d'une variable de 1 si son type est number
et affecte 0 à la variable sinon, où la variable est initialement null
ou undefined
.
La première implémentation était v >= 0 ? v += 1 : v = 0
Parce que je pensais que tout ce qui n'était pas un nombre ferait une expression arithmétique fausse, mais c'était faux puisque null >= 0
Est évalué comme vrai. J'ai ensuite appris que null
se comportait comme 0 et que les expressions suivantes étaient toutes évaluées à true.
null >= 0 && null <= 0
!(null < 0 || null > 0)
null + 1 === 1
1 / null === Infinity
Math.pow(42, null) === 1
Bien sûr, null
n'est pas 0. null == 0
Est évalué à false. Cela rend l'expression apparemment tautologique (v >= 0 && v <= 0) === (v == 0)
Fausse.
Pourquoi null
est-il comme 0, bien qu'il ne soit pas réellement 0?
Votre vraie question semble être:
Pourquoi:
null >= 0; // true
Mais:
null == 0; // false
Ce qui se passe vraiment, c'est que Opérateur supérieur ou égal (>=
), exécute la contrainte de type ( ToPrimitive
), avec un indice de Number
, en fait tous les opérateurs relationnels ont ce comportement.
null
est traité d'une manière spéciale par l'opérateur Equals (==
). En bref, il ne fait que contraindre à undefined
:
null == null; // true
null == undefined; // true
Des valeurs telles que false
, ''
, '0'
, et []
sont soumis à une contrainte de type numérique, tous contraignent à zéro.
Vous pouvez voir les détails internes de ce processus dans les The Abstract Equality Comparison Algorithm et The Abstract Relational Comparison Algorithm .
En résumé:
Comparaison relationnelle: si les deux valeurs ne sont pas de type String, ToNumber
est appelé sur les deux. Cela revient à ajouter un +
devant, ce qui pour null contraint à 0
.
Comparaison d'égalité: appelle uniquement ToNumber
sur les chaînes, les nombres et les booléens.
Je voudrais étendre la question pour améliorer encore la visibilité du problème:
null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0; //false
null < 0; //false
Cela n'a aucun sens. Comme les langues humaines, ces choses doivent être apprises par cœur.
JavaScript a des comparaisons strictes et de conversion de type
null >= 0;
Est vrai mais (null==0)||(null>0)
Est faux
null <= 0;
Est vrai mais (null==0)||(null<0)
Est faux
"" >= 0
Est également vrai
Pour les comparaisons abstraites relationnelles (<=,> =), les opérandes sont d'abord convertis en primitives, puis dans le même type, avant la comparaison.
typeof null returns "object"
Lorsque le type est un objet, javascript essaie de stringifier l'objet (c'est-à-dire nul), les étapes suivantes sont prises ( ECMAScript 2015 ):
PreferredType
n'a pas été transmis, laissez hint
être "par défaut".PreferredType
est hint
String, soit hint
soit "string".PreferredType
est hint
Number, que hint
soit "number".exoticToPrim
soit GetMethod(input, @@toPrimitive)
.ReturnIfAbrupt(exoticToPrim)
.exoticToPrim
n'est pas indéfini, alorsCall(exoticToPrim, input, «hint»)
.ReturnIfAbrupt(result)
.Type(result)
n'est pas Object, retourne le résultat.hint
est "par défaut", soit hint
soit "nombre".OrdinaryToPrimitive(input,hint)
.Les valeurs autorisées pour l'indice sont "par défaut", "nombre" et "chaîne". Les objets de date sont uniques parmi les objets ECMAScript intégrés en ce qu'ils traitent "default" comme étant équivalent à "string". Tous les autres objets ECMAScript intégrés traitent "default" comme étant équivalent à "number" . ( ECMAScript 20.3.4.45 )
Je pense donc que null
se transforme en 0.
J'ai eu le même problème !!. Actuellement, ma seule solution est de se séparer.
var a = null;
var b = undefined;
if (a===0||a>0){ } //return false !work!
if (b===0||b>0){ } //return false !work!
//but
if (a>=0){ } //return true !