Introduction : Le problème qui a fait exploser Stack Overflow
\n\nImaginez la scène : vous êtes en entretien, et le recruteur, avec un sourire en coin, vous demande : « L'expression a == 1 && a == 2 && a == 3 peut-elle un jour renvoyer true ? ». La première réaction est : « Bien sûr que non ! Une seule variable ne peut pas être égale à trois nombres différents à la fois. »
Cependant, si vous connaissez un peu mieux JavaScript, vous savez que ce langage est capable des choses les plus inattendues. Cette question a cumulé des milliers de vues sur Stack Overflow et est devenue un classique pour tester la compréhension de la coercition de types, des getters et des wrappers d'objets en JS.
\n\nDans cet article, non seulement nous prouverons que c'est possible, mais nous analyserons également 5 méthodes différentes pour faire en sorte que (a==1 && a==2 && a==3) renvoie true. Vous découvrirez comment fonctionne la comparaison non stricte (==), en quoi elle diffère de la comparaison stricte (===), et comment la contrôler.
Cet article sera utile aussi bien aux débutants souhaitant approfondir leur compréhension de JavaScript, qu'aux développeurs expérimentés se préparant pour un entretien. C'est parti !
\n\nMéthode n°1 : La magie de valueOf (la plus populaire)
\n\nLa méthode la plus élégante et la plus souvent citée consiste à utiliser un objet personnalisé avec une méthode valueOf redéfinie. En JavaScript, lorsque vous comparez un objet à une valeur primitive avec ==, le moteur appelle automatiquement valueOf() (ou toString()) pour convertir l'objet en primitive.
Nous allons créer un objet-compteur qui, à chaque appel de valueOf, augmentera sa valeur de 1.
const a = {\n valeur: 1,\n valueOf() {\n return this.valeur++;\n }\n};\n\nconsole.log(a == 1 && a == 2 && a == 3); // true\n\nComment ça marche :
\n- \n
- Lors de la première comparaison
a == 1,valueOf()est appelée, retourne 1, etvaleurpasse à 2. \n - Lors de la deuxième comparaison
a == 2,valueOf()est appelée à nouveau, retourne 2, etvaleurdevient 3. \n - La troisième comparaison
a == 3termine la chaîne avec succès. \n
C'est un exemple parfait de type coercion (coercition de types) en action. C'est ce mécanisme qui rend JavaScript à la fois un langage flexible et dangereux.
\n\nMéthode n°2 : toString — le jumeau de valueOf
\n\nSi vous redéfinissez toString au lieu de valueOf, le résultat sera le même. JavaScript, lors d'une comparaison non stricte, peut utiliser l'une ou l'autre de ces méthodes pour convertir un objet.
const a = {\n valeur: 1,\n toString() {\n return this.valeur++;\n }\n};\n\nconsole.log(a == 1 && a == 2 && a == 3); // true\n\nLa différence est subtile : valueOf a la priorité pour les comparaisons numériques, tandis que toString est prioritaire pour les comparaisons de chaînes. Mais dans notre cas, les deux approches fonctionnent parfaitement.
Méthode n°3 : Les getters dans la portée globale
\n\nBeaucoup de gens ignorent que les variables globales en JavaScript sont en réalité des propriétés de l'objet global (window dans le navigateur, global dans Node.js). Et les propriétés peuvent être définies via des getters.
Nous pouvons définir un getter pour la variable a directement sur l'objet global :
let valeur = 1;\nObject.defineProperty(window, 'a', {\n get() {\n return valeur++;\n }\n});\n\nconsole.log(a == 1 && a == 2 && a == 3); // true\n\nCette méthode est particulièrement intéressante car a se comporte comme une variable ordinaire, alors qu'il s'agit en réalité d'une propriété avec un getter. Chaque fois que vous accédez à a, le getter renvoie une nouvelle valeur.