W3docs

Comprendre la conversion d'objet en primitif en JavaScript

Apprenez comment JavaScript convertit les objets en primitifs : les hints string, number et default, Symbol.toPrimitive, et la chaîne de repli toString/valueOf, avec des exemples exécutables.

Introduction à la conversion d'objet en primitif

En JavaScript, les objets sont des valeurs de référence, mais de nombreuses opérations attendent une valeur primitive (une string, un nombre ou un boolean). Lorsque vous écrivez obj + "", +obj, ou `${obj}`, le langage doit d'abord transformer l'object en primitif avant de pouvoir exécuter l'opération. C'est ce qu'on appelle la conversion d'objet en primitif.

Ce guide explique les règles que JavaScript suit : les trois hints de conversion ("string", "number", "default"), la méthode Symbol.toPrimitive qui vous permet de contrôler la conversion, et la chaîne de repli toString()/valueOf() utilisée lorsque Symbol.toPrimitive est absent.

Comment fonctionne la conversion d'objet en primitif

Il n'existe pas d'opérateur qui convertit un object en boolean — les objets sont toujours véridiques dans un contexte boolean. La conversion d'objet en primitif ne produit donc jamais qu'une string ou un nombre, et JavaScript décide lequel cibler en passant un hint à l'object :

  1. Il recherche d'abord une méthode [Symbol.toPrimitive](hint). Si elle est présente, elle est appelée et sa valeur de retour (qui doit être une valeur primitive) est utilisée.
  2. Si Symbol.toPrimitive est absent, JavaScript se rabat sur toString() et valueOf(), en les appelant dans un ordre qui dépend du hint.

Nous aborderons le mécanisme de repli en détail plus tard. Voyons d'abord l'approche moderne et explicite.

Exemple : implémenter Symbol.toPrimitive

javascript— editable

Explication : L'object user définit une seule méthode Symbol.toPrimitive qui se branche sur le hint. Un template literal demande un hint "string", la multiplication demande "number", et l'opérateur binaire + demande "default". Retourner this.money pour le cas par défaut garantit la cohérence des calculs arithmétiques avec + comme avec *.

Comprendre les hints de conversion

Un hint est une string que le moteur passe pour indiquer à votre object quel type de primitif l'opération préfère :

  • "string" : le résultat est censé être une string — String(obj), `${obj}`, alert(obj), ou un object utilisé comme clé de propriété.
  • "number" : un résultat numérique est attendu — +obj unaire, obj * 2, obj - 1, obj < other, Number(obj), Math.round(obj).
  • "default" : l'opérateur accepte l'un ou l'autre type et ne sait pas lequel demander. C'est plus rare qu'on ne le pense, mais cela compte : l'opérateur binaire + (qui peut désigner à la fois l'addition et la concaténation de strings) utilise "default", tout comme les opérateurs d'égalité souple == / != lors de la comparaison d'un object avec un nombre ou une string.

Une surprise fréquente : obj + "" n'utilise pas le hint "string" — il utilise "default". Si vous ne gérez que "string" et "number", c'est la branche "default" qui s'exécute pour +.

Exemple : gérer différents hints

javascript— editable

Explication : Ici, l'object item gère les trois hints. Notez la dernière ligne : comme l'opérateur binaire + utilise le hint "default", item + '' exécute la branche "default" — et non la branche "string" — produisant "Item: Chair, Price: 45". C'est précisément ce genre de subtilité qui justifie de gérer explicitement chaque hint. Voir aussi les opérateurs de comparaison et les opérateurs numériques.

La chaîne de repli toString / valueOf

Si un object ne possède pas de méthode Symbol.toPrimitive, JavaScript utilise l'ancienne paire de méthodes et choisit l'ordre en fonction du hint :

  • Pour un hint "string" : essayez d'abord toString(), puis valueOf().
  • Pour un hint "number" ou "default" : essayez d'abord valueOf(), puis toString().

Dans chaque cas, il utilise la première méthode qui retourne une valeur primitive ; si une méthode retourne un object, elle est ignorée et la suivante est essayée. Un object simple hérite de Object.prototype.toString (qui retourne "[object Object]") et de Object.prototype.valueOf (qui retourne l'object lui-même, donc il est ignoré) — c'est pourquoi ({}) + "" vaut "[object Object]".

javascript— editable

Explication : Sans Symbol.toPrimitive, le hint "string" atteint toString() et retourne "John", tandis que les hints numérique et par défaut atteignent valueOf() et retournent 1000. Symbol.toPrimitive est préférable pour le nouveau code car il offre un endroit unique et explicite pour gérer chaque hint ; toString/valueOf restent utiles lorsque vous ne vous souciez que d'une seule direction.

Bonnes pratiques pour utiliser toPrimitive

Implémenter Symbol.toPrimitive efficacement suppose de combiner clarté, cohérence et tests approfondis pour s'assurer que les objets se comportent de manière prévisible lors de leur conversion en primitifs. Voici comment appliquer ces bonnes pratiques lors de l'utilisation de la méthode Symbol.toPrimitive :

1. Sémantique claire

Bonne pratique : Définissez Symbol.toPrimitive clairement pour rendre les conversions d'objets prévisibles et compréhensibles. Cela implique de gérer explicitement les différents types de hints de conversion ("string", "number" et "default") et de fournir des valeurs de retour appropriées pour chaque cas.

Exemple :

javascript— editable

Explication : Dans cet exemple, l'object dateEvent définit clairement les comportements de conversion pour les contextes string et number. Pour les conversions en string, il retourne une description, et pour les conversions en number, il retourne le timestamp de l'événement. Cette distinction claire aide les autres développeurs à comprendre ce qui est attendu lors de la conversion de l'object dans différents contextes.

2. Cohérence

Bonne pratique : Assurez-vous que les conversions sont cohérentes avec les données de l'object et son utilisation prévue, en évitant des comportements confus ou illogiques.

javascript— editable

Explication : L'object product garantit que la logique de conversion est cohérente avec ses propriétés. Qu'il soit converti en string pour l'affichage ou en number pour des calculs, le résultat reste intuitif et utile, respectant l'usage prévu de chaque propriété.

3. Tests

Bonne pratique : Testez soigneusement le comportement de vos objets dans différents scénarios de conversion afin d'éviter des bugs inattendus dans votre application.

Exemples d'approches de test :

  • Tests unitaires : Rédigez des tests unitaires qui tentent de convertir l'object à l'aide de différentes opérations (comme des opérations arithmétiques, la concaténation de strings, ou le passage de l'object à des fonctions attendant un type primitif) pour s'assurer que tous les scénarios retournent les valeurs attendues.
// Note: In a browser environment, use console.assert or a test framework like Jest/Mocha.
// Assumes 'product' is defined as in the previous example.
console.assert(String(product) === "Laptop costs $1200", "String conversion failed");
console.assert(+product === 1200, "Number conversion failed");
console.assert(product + '' === "Laptop", "Default conversion failed");

Explication : Grâce aux tests unitaires, vous pouvez vérifier que l'object product gère correctement toutes les formes de conversions selon la logique définie dans Symbol.toPrimitive. Cela garantit la fiabilité et la cohérence de la façon dont votre object interagit avec les différentes parties du moteur JavaScript et de votre application.

Pièges courants

  • Il n'existe pas de hint boolean. Dans un contexte boolean (if (obj), !obj, obj && x), l'object est toujours véridique et n'est jamais converti en primitif. La conversion d'objet en primitif ne produit que des strings et des nombres.
  • + utilise "default", pas "string". Cela piège de nombreux développeurs : obj + "" déclenche le hint par défaut. Les comparaisons comme obj == 5 utilisent aussi "default".
  • Une méthode doit retourner une valeur primitive. Si Symbol.toPrimitive (ou valueOf/toString) retourne un object au lieu d'une valeur primitive, vous obtenez une TypeError. Pour la paire de repli, retourner un object fait simplement que cette méthode est ignorée.
  • La conversion numérique d'un résultat string peut donner NaN. Si votre branche "number"/"default" retourne une string non numérique, les contextes attendant un nombre obtiennent NaN : +{ [Symbol.toPrimitive]: () => "abc" } vaut NaN.

Conclusion

La conversion d'objet en primitif est un mécanisme fondamental de JavaScript qui permet aux objets de participer aux opérations arithmétiques, à la concaténation de strings et aux opérations de comparaison. Le moteur choisit un hint ("string", "number" ou "default"), essaie d'abord Symbol.toPrimitive, puis se rabat sur toString()/valueOf(). En implémentant Symbol.toPrimitive, vous disposez d'un endroit unique et explicite pour contrôler le comportement d'un object personnalisé dans chaque contexte — ce qui conduit à un code plus prévisible et plus maintenable. Pour aller plus loin, consultez les types de données, les types de symboles et les méthodes d'objet et this.

Pratique

Pratique
Lorsque vous évaluez obj + '' et que obj possède une méthode Symbol.toPrimitive, quel hint JavaScript passe-t-il ?
Lorsque vous évaluez obj + '' et que obj possède une méthode Symbol.toPrimitive, quel hint JavaScript passe-t-il ?
Pratique
Si un object n'a pas de méthode Symbol.toPrimitive, dans quel ordre JavaScript essaie-t-il pour le hint 'number' ?
Si un object n'a pas de méthode Symbol.toPrimitive, dans quel ordre JavaScript essaie-t-il pour le hint 'number' ?
Was this page helpful?