mozilla

L'égalité en JavaScript

EcmaScript6 possède trois outils pour déterminer si deux valeurs x et y sont « égales ».  Il y a l'égalité simple (deux signes égal) (==), l'égalité stricte (trois signes égal) (===), et la méthode Object.is. (Cette méthode a été ajoutée avec ES6. Les opérateurs d'égalité simple et stricte étaient présents en JavaScript avant ES6 et ont conservé leur comportement.)

Un aperçu

Voici comment utiliser chacun de ces outils de comparaisons :

x == y
x === y
Object.is(x, y)

En résumé : l'opérateur d'égalité simple effectuera une conversion de type entre les objets comparés, l'opérateur d'égalité stricte n'effectuera pas de conversion avant de comparer les objets (false est renvoyé automatiquement si les types sont différents), enfin Object.is se comportera de la même façon que l'opérateur d'égalité stricte avec des règles supplémentaires pour les valeurs NaN, -0 et +0. Object.is(-0, +0) ne sera pas vérifié et Object.is(NaN, NaN) sera vrai. (Généralement, quand on compare NaN et NaN, on obtient le résultat false car la norme IEEE 754 indique que ce comportement est celui attendu pour l'égalité simple ou stricte.)

Cette égalité ne s'applique qu'aux types de données primitifs, aucune des méthodes présentées ci-avant ne permet de comparer la structure de deux objets. Si deux objets x et y possèdent la même structure mais que ce sont des objets distincts, chacune de ces méthodes renverra le résultat false.

Ainsi :

let x = { valeur: 17 };
let y = { valeur: 17 };
console.log(Object.is(x, y)); // false;
console.log(x === y);         // false
console.log(x == y);          // false

Les égalités simples, strictes et les valeurs identiques

Les comparaisons effectuées par les opérateurs d'égalité simple et d'égalité stricte sont décrites par EcmaScript5 : l'algorithme de l'opérateur == est décrit dans la section 11.9.3 (en anglais) et l'algorithme de l'opérateur === est décrit dans la section 11.9.6 (en anglais). Ces deux algorithmes sont expliqués de façon simple et concise, il est préferable de lire le deuxième algorithme avant le premier. ES5 décrit également l'algorithme utilisé en interne par le moteur JavaScript : section 9.12, The SameValue Algorithm (en anglais). Ce dernier algorithme est très proche de celui utilisé pour l'égalité stricte, ils différent de par leurs gestions différentes des nombres représentés sous forme d'objets Number. Object.is n'est que la retranscription de cet algorithme, utilisable depuis ES6.

Excepté pour la conversion implicite, on peut voir que, pour les opérateurs d'égalité simple et stricte, l'algorithme d'égalité stricte est un sous-ensemble de l'égalité simple car 11.9.6.2-7 correspond à 11.9.3.1.a-f.

Comprendre le sens des différentes égalités

Avant ES6, on pouvait penser que l'égalité stricte était une version « améliorée » de l'égalité simple, ou vice-versa. Par exemple, dans certains cas, on peut trouver que l'égalité simple est plus souple que l'égalité stricte car elle effectue une conversion des types (ce qui permet de vérifier 6 == "6"). Au contraire, on peut trouver que l'égalité stricte est « meilleure » que l'égalité simple car il est nécessaire que les deux opérandes soient du même type. L'utilité de chaque opérateur dépend du cadre dans lequel on l'utilise.

Object.is, en revanche, n'est pas plus souple ou plus stricte que ces égalités. Il n'est pas non plus un « intermédiaire » entre ces deux opérateurs. Object.is diffère dans sa façon de gérer la valeur numérique spéciale NaN. D'une certaine façon, Object.is se différencie en fonction de ses caractéristiques spéciales sur NaN et -0 et +0.

Opérateurs d'égalité
x y == === Object.is
undefined undefined true true true
null null true true true
true true true true true
false false true true true
"toto" "toto" true true true
{ toto: "truc" } x true true true
0 0 true true true
+0 -0 true true false
0 false true false false
"" false true false false
"" 0 true false false
"0" 0 true false false
"17" 17 true false false
new String("toto") "toto" true false false
null undefined true false false
null false false false false
undefined false false false false
{ toto: "truc" } { toto: "truc" } false false false
new String("toto") new String("toto") false false false
0 null false false false
0 NaN false false false
"toto" NaN false false false
NaN NaN false false true

Dans quels cas utiliser Object.is ou l'opérateur d'égalité stricte

En dehors du traîtement effectué pour NaN, Object.is s'avère utile lorsqu'on manipule des valeurs très proches de 0 (parfois utilisées pour la métaprogrammation et notamment pour les descripteurs de propriétés et qu'on souhaite reproduire certaines caractéristiques de Object.defineProperty). Si on n'a pas ce cas de figure à gérer, il est conseillé d'utiliser ===. Même dans l'éventualité où on devrait gérer une comparaison entre deux valeurs NaN il est souvent plus facile de traiter le cas particulier en utilisant la fonction isNaN présente dans les anciennes versions d'ECMAScript.

Voici une liste (non exhaustive) des méthodes et opérateurs qui pourraient entraîner une apparition des valeurs -0 et +0 :

- (négation unaire)

Il peut sembler évident que l'opposé de 0 est -0 mais lorsque que cette opération est réalisée dans une expression, il est plus facile d'identifier la transformation qui s'est effectuée. Par exemple :

let forceFrottement = obj.masse * -obj.vitesse

Si obj.vitesse vaut 0, on aura -0 comme résultat du calcul, et c'est cette valeur qui sera assignée à forceFrottement

Math.atan2
Math.ceil
Math.pow
Math.round
La valeur -0 peut être produite par ces méthodes (et donc introduite dans une expression qui les comportent), même dans le cas où -0 n'est pas un argument. Par exemple, si on utilise Math.pow pour calculer -Infinity à une puissance entière impaire et négative, on obtiendra -0. Voir les différentes pages sur ces méthodes pour plus d'informations.
Math.floor
Math.max
Math.min
Math.sin
Math.sqrt
Math.tan
Ces méthodes peuvent produire la valeur -0 si c'est un des paramètres de la fonction. Par exemple, Math.min(-0, +0) vaudra -0. Voir les différentes pages sur ces méthodes pour plus d'informations.
~
<<
>>
Chacun de ces opérateurs utilise l'algorithme ToInt32. Or, il n'y a qu'une seule représentation possible pour 0 sous forme d'un entier sur 32 bits, c'est pourquoi -0 ne pourra pas être « conservé » par une combinaison de ces opérations (même si cette combinaison est équivalente, logiquement, à une identité). Par exemple Object.is(~~(-0), -0) et Object.is(-0 << 2 >> 2, -0) produiront la valeur false.

Il peut être dangereux d'utiliser Object.is quand on ne souhaite pas différencier les deux valeurs -0 et +0. En revanche, si on souhaite distinguer ces deux valeurs, cette fonction est idéale.

Étiquettes et contributeurs liés au document

Contributeurs à cette page : teoli, SphinxKnight
Dernière mise à jour par : SphinxKnight,
Masquer la barre latérale