[ Web Proxy ]
URL:
Viewing: https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Equality_comparisons_and_sameness [Back]  [Original]

Utiliser les diffrents tests d'galit - JavaScript | MDN

Cette page a t traduite partir de l'anglais par la communaut. Vous pouvez contribuer en rejoignant la communaut francophone sur MDN Web Docs.

View in English Always switch to English

Utiliser les diffrents tests d'galit

JavaScript fournit trois oprations permettant de comparer des valeurs :

  • L'galit stricte (ou identit ou triple gal ) utilisant ===,
  • L'galit faible (ou double gal ) utilisant ==,
  • Object.is (ajout avec ECMAScript 2015).

Ces trois oprations sont associes quatre algorithmes d'galit (depuis ES2015) :

Selon la comparaison qu'on souhaite effectuer, on choisira une de ces oprations.

En rsum :

  • L'galit faible (==) effectuera une conversion des deux lments comparer avant d'effectuer la comparaison
  • L'galit stricte (===) effectuera la mme comparaison mais sans conversion pralable (elle renverra toujours false si les types des deux valeurs compares sont diffrents)
  • Enfin Object.is() se comportera comme l'galit stricte sauf pour les valeurs NaN, -0 et +0 : pour Object.is(), -0 et +0 seront diffrents mais on aura Object.is(NaN, NaN) qui sera true. (Gnralement, quand on compare NaN avec NaN en utilisant l'galit stricte ou l'galit faible, cela donne false afin de respecter la norme IEEE 754.)

On notera que pour ces trois oprations, la comparaison s'effectue sur les valeurs des lments qu'on compare, aucune de ces oprations ne permet de comparer la structure des paramtres. Pour des objets non primitifs, x et y qui ont la mme structure mais qui sont des objets distincs, chacune des oprations prsentes ci-avant sera value false.

Dans cet article

L'galit stricte avec ===

L'galit stricte compare deux valeurs et teste leur galit. Aucune des valeurs n'est convertie implicitement en une autre valeur avant que la comparaison soit effectue. Si les valeurs sont types diffremment, elles sont considres comme diffrentes. Si les valeurs sont de mme type et ne sont pas des nombres, elles sont considres gales si elles ont la mme valeur. Si les deux valeurs sont des nombres, elles sont gales si elles ont la mme valeur et que cette valeur n'est pas NaN ou si l'une vaut +0 et l'autre -0.

js
var num = 0;
var obj = new String("0");
var str = "0";

console.log(num === num); // true
console.log(obj === obj); // true
console.log(str === str); // true

console.log(num === obj); // false
console.log(num === str); // false
console.log(obj === str); // false
console.log(null === undefined); // false
console.log(obj === null); // false
console.log(obj === undefined); // false

Ce test d'galit stricte est presque toujours la meilleure des oprations considrer pour ces tests. Except pour les nombres, la smantique utilise est simple : une valeur est uniquement gale elle-mme. En ce qui concerne les nombres, il y a deux cas aux limites considrer. Le premier cas concerne le nombre zro positif ou ngatif. Cela peut tre utile dans la reprsentation de problmes mathmatiques mais ne constitue pas une diffrence pour de nombreuses situations : le test d'galit stricte considre que ce sont les mmes valeurs. Le second cas concerne la valeur n'est pas un nombre , NaN (pour not a number en anglais) permettant de reprsenter certaines entits mathmatiques : la somme des deux infinis (positif et ngatif) par exemple. Le test d'galit stricte considre que NaN est diffrent de toutes les valeurs, y compris lui-mme. (N.B. : Le seul cas de figure pour lequel on a (x !== x) qui renvoie true est lorsque x vaut NaN.)

L'galit faible avec ==

Le test d'galit faible compare deux valeurs aprs les avoir converties en valeurs d'un mme type. Une fois converties (la conversion peut s'effectuer pour l'une ou les deux valeurs), la comparaison finale est la mme que celle effectue par ===. L'galit faible est symtrique : A == B aura toujours la mme signification que B == A pour toute valeur de A et B.

La comparaison d'galit est effectue comme suit pour des oprandes de diffrents types :

Oprande B
Undefined Null Number String Boolean Object
Oprande A Undefined true true false false false false
Null true true false false false false
Number false false A === B A === ToNumber(B) A === ToNumber(B) A == ToPrimitive(B)
String false false ToNumber(A) === B A === B ToNumber(A) === ToNumber(B) A == ToPrimitive(B)
Boolean false false ToNumber(A) === B ToNumber(A) === ToNumber(B) A === B false
Object false false ToPrimitive(A) == B ToPrimitive(A) == B ToPrimitive(A) == ToNumber(B)

A === B

Dans le tableau ci-dessus, l'expression ToNumber(A) correspond une tentative de convertir l'argument en un nombre avant la comparaison. Le rsultat obtenu est quivalent +A (l'oprateur unaire +). ToPrimitive(A) correspond une tentative de convertir l'argument en une valeur primitive grce plusieurs mthodes comme A.toString et A.valueOf.

Selon ECMAScript, au sens de l'galit faible, tous les objets sont diffrents de undefined et de null. Cependant, la plupart des navigateurs autorisent, dans certains contextes, unensemble restreint d'objets (notamment l'objet document.all), agir comme s'ils mulaient la valeur undefined. L'galit faible est un de ces contextes. Pour tous les autres cas, un objet ne sera jamais approximativement gal undefined ou null.

js
var num = 0;
var obj = new String("0");
var str = "0";

console.log(num == num); // true
console.log(obj == obj); // true
console.log(str == str); // true

console.log(num == obj); // true
console.log(num == str); // true
console.log(obj == str); // true
console.log(null == undefined); // true

// Les deux assertions qui suivent sont fausses
// sauf dans certains cas exceptionnels
console.log(obj == null);
console.log(obj == undefined);

Certains dveloppeurs considrent que ce n'est jamais une bonne ide d'utiliser l'galilt faible. Le rsultat d'une comparaison utilisant l'galit stricte est plus simple apprhender et prdire, de plus il n'y a aucune conversion implicite ce qui rend le test plus rapide.

galit de valeurs

L'galit de valeurs rpond un dernier cas d'utilisation : savoir si deux valeurs sont fonctionnellement identiques pour tout contexte. (Ce cas d'utilisation est un exemple du principe de substitution de Liskov). On retrouve ce cas lorsqu'on essaie de changer une proprit immuable :

js
// Ajouter la proprit immuable NEGATIVE_ZERO au constructor Number.
Object.defineProperty(Number, "NEGATIVE_ZERO", {
  value: -0,
  writable: false,
  configurable: false,
  enumerable: false,
});

function attemptMutation(v) {
  Object.defineProperty(Number, "NEGATIVE_ZERO", { value: v });
}

Object.defineProperty lancera une exception pour tout changement de la proprit qui serait rellement un changement. Rien ne se passera si aucun changement n'est ncessaire. Ainsi, si v vaut -0, aucun changement n'est ncessaire et il n'y aura pas d'erreur. Mais si v vaut +0, Number.NEGATIVE_ZERO n'aurait plus la mme valeur immuable. De faon interne l'implmentation, la nouvelle valeur est compare avec la valeur courante en utilisant une galit de valeurs.

L'galit de valeurs peut tre teste grce la mthode Object.is.

galit de valeurs nulles

On utilise la mme galit que l'galit de valeur et on considre que +0 et -0 sont gaux.

galit abstraite, galit stricte et valeurs identiques : la spcification

Selon ES5, la comparaison effectue par == est dcrite dans la section 11.9.3 sur l'algorithme d'galit abstraite (Abstract Equality Algorithm). La comparaison donne par === est dcrite dans la section 11.9.6 sur l'algorithme d'galit stricte (Strict Equality Algorithm). Ces documents sont en anglais mais sont tout fait abordables, ne pas hsiter les consulter (conseil : d'abord commencer par l'algorithme d'galit stricte). ES5 dcrit galement, dans la section 9.12 sur l'algorithme SameValue, l'opration utilise en interne par le moteur JavaScript. Cet algorithme est principalement bas sur l'algorithme d'galit stricte : 11.9.6.4 et 9.12.4 diffrent en ce qui concerne les nombres. ES6 (ECMAScript 2015) permet d'utiliser cet algorithme grce la mthode Object.is.

Dans ces documents, on peut voir que l'algorithme d'galit stricte est un sous-ensemble de l'algorithme d'galit abstraite (exception faite de la vrification du type) car 11.9.6.27 correspond exactement 11.9.3.1.af.

Un modle pour mieux comprendre ?

Avant ES6 (ECMAScript 2015), il tait courant de dire que l'galit stricte avec le triple gal tait une version amliore de l'galit faible (double gal) et vice versa. En effet, l'galit faible ajoute une tape de conversion des types qui n'est pas fournie par l'galit stricte (ce qui permet d'avoir 6 == "6"). On peut aussi dire que l'galit stricte est une version amliore de l'galit simple car elle ajoute une fonctionnalit de vrification des types. Selon votre approche et votre problme, une de ces galits se prtera mieux la rsolution.

Cependant, ce modle de penses ne peut pas tre tendu avec l'arrive d'Object.is avec ES6 (ECMAScript 2015). En effet Object.is() n'est pas plus faible que l'galit faible ou plus stricte que l'galit stricte et il n'est pas non plus quelque part entre les deux. Dans le tableau de comparaison ci-aprs, on voit que la diffrence provient avant tout de la faon dont Object.is gre NaN. On note ici que si Object.is(NaN, NaN) valait false, on pourrait dire qu'Object.is() est plus stricte que == ou === car elle distingue -0 et +0. Cependant, ce n'est pas le cas et on a bien Object.is(NaN,NaN) qui vaut true. C'est pour cette raison qu'il faut considrer Object.is selon ses caractristiques spcifiques plutt que comme une version plus faible ou plus stricte des autres oprateurs d'galit.

x y == === Object.is SameValueZero
undefined undefined true true true true
null null true true true true
true true true true true true
false false true true true true
'toto' 'toto' true true true true
0 0 true true true true
+0 -0 true true false true
+0 0 true true true true
-0 0 true true false true
0 false true false false false
"" false true false false false
"" 0 true false false false
'0' 0 true false false false
'17' 17 true false false false
[1, 2] '1,2' true false false false
new String('toto') 'toto' true false false false
null undefined true false false false
null false false false false false
undefined false false false false false
{ toto: 'truc' } { toto: 'truc' } false false false false
new String('toto') new String('toto') false false false false
0 null false false false false
0 NaN false false false false
'toto' NaN false false false false
NaN NaN false false true true

Quand utiliser Object.is et quand utiliser l'galit stricte

En plus de la faon dont Object.is traite NaN, la spcificit d'Object.is() rside dans sa faon de traiter les valeurs proches de zro. Dans des cas d'utilisation o on a besoin d'effectuer de la mta-programmation, notamment pour imiter certaines caractristiques de Object.defineProperty. Si le scnario d'utilisation ne ncessite pas ce comportement, il est conseill d'utiliser ===. Mme si on souhaite pouvoir comparer NaN avec lui-mme et que ce test vaille true, il sera plus simple d'utiliser la mthode isNaN disponible avec les versions antrieures d'ECMAScript. En effet, cela vite d'avoir traiter des cas plus complexes o il faudrait grer les signes des zros dans les diffrentes comparaisons.

Voici une liste (non exhaustive) d'oprateurs et de mthodes natives qui peuvent entraner l'apparition des valeurs -0 et +0 dans le code :

- (ngation unaire)

Si on prend l'oppos de 0, on aura, bien entendu, -0. Cependant, avec les expressions, cela peut faire que la valeur -0 se glisse dans les variables sans qu'on s'en rende compte. Par exemple :

js
let forceArrt = obj.masse * -obj.vitesse;

Si obj.vitesse vaut 0 (ou est valu 0), un -0 sera introduit, ce qui fera que forceArrt pourra tre ngative.

Math.atan2, Math.ceil, Math.pow, Math.round

Ces mthodes peuvent introduire -0 dans une expression lors de leur valuation, mme si -0 ne faisait pas partie des paramtres. Par exemple, si on utilise Math.pow() pour lever -Infinity une puissance ngative, on obtiendra -0 pour une puissance impaire. Pour plus de dtails, voir la documentation de chaque mthode.

Math.floor, Math.max, Math.min, Math.sin, Math.sqrt, Math.tan

Ces mthodes peuvent renvoyer -0 dans certains cas o -0 est pass en paramtre. Par exemple, Math.min(-0, +0) fournira -0. Pour plus de dtails, voir la documentation de chaque mthode.

~, <<, >>

Chacun de ces oprateurs utilise l'algorithme ToInt32 interne au moteur JavaScript. tant donn qu'il n'y a qu'une seule reprsentation pour 0 sur les entiers exprims avec le type interne sur 32 bits, -0 ne sera pas invariant pour deux oprations symtriques : Object.is(~~(-0), -0) et Object.is(-0 << 2 >> 2, -0) renverront tous les deux false.

Si on utilise Object.is et qu'on ne souhaite pas grer les cas aux limites autour de zro, cela peut avoir des effet indsirs. En revanche, si on souhaite effectivement comparer -0 et +0, c'est la mthode adopter.

Voir aussi


Web Proxy Viewer  |  New URL  |  Original Page