web-dev-qa-db-fra.com

Pourquoi `null> = 0 && null <= 0` mais pas` null == 0`?

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?

134
C. Lee

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.

200
CMS

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.

13
estani

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 ):

  1. Si PreferredType n'a pas été transmis, laissez hint être "par défaut".
  2. Sinon si PreferredType est hint String, soit hint soit "string".
  3. Sinon PreferredType est hint Number, que hint soit "number".
  4. Soit exoticToPrim soit GetMethod(input, @@toPrimitive).
  5. ReturnIfAbrupt(exoticToPrim).
  6. Si exoticToPrim n'est pas indéfini, alors
    a) Soit le résultat Call(exoticToPrim, input, «hint»).
    b) ReturnIfAbrupt(result).
    c) Si Type(result) n'est pas Object, retourne le résultat.
    d) Lancez une exception TypeError.
  7. Si hint est "par défaut", soit hint soit "nombre".
  8. Renvoie 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.

4
Panos Kal.

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 !
1
jon