W3docs

Méthodes de prototype JavaScript sans __proto__

Découvrez les méthodes modernes de prototype JavaScript : Object.create(), getPrototypeOf(), setPrototypeOf() et les objets sans prototype pour des dictionnaires sûrs.

Chaque object JavaScript est lié à un autre object appelé son prototype, et la recherche de propriétés remonte cette chaîne. L'ancienne façon de lire ou modifier ce lien était la propriété spéciale __proto__, mais elle présente de vrais problèmes : c'est un accesseur hérité (pas un emplacement de données ordinaire), elle se comporte de façon incohérente en tant que clé d'object, et elle peut être exploitée pour corrompre des objets. JavaScript moderne la remplace par des méthodes explicites et prévisibles sur le constructeur Object.

Ce chapitre présente les méthodes de prototype standard — Object.create(), Object.getPrototypeOf() et Object.setPrototypeOf() — ainsi que les utilitaires d'inspection Object.keys(), Object.values(), Object.entries() et Object.hasOwn(). Il aborde ensuite le cas le plus utile d'un object sans prototype : un « dictionnaire » sûr pour des clés arbitraires.

Pour une vue d'ensemble du fonctionnement de la chaîne, voir Héritage prototypal et au-delà.

Lire et définir un prototype

Utilisez Object.getPrototypeOf() pour lire le prototype d'un object et Object.setPrototypeOf() pour le modifier. Ce sont les remplaçants standardisés pour la lecture et l'écriture de __proto__.

javascript— editable

Object.create(proto) construit un tout nouvel object dont le prototype est exactement proto. C'est la façon la plus propre de créer un object avec un prototype choisi sans utiliser __proto__ du tout.

Pourquoi éviter __proto__

__proto__ est un getter/setter défini sur Object.prototype, pas une propriété qui réside sur votre object. Cette différence cause deux problèmes pratiques :

  • Il peut échouer ou se comporter étrangement en tant que clé de données. Parce que obj.__proto__ = value déclenche le setter, vous ne pouvez pas stocker de façon fiable une clé littéralement nommée "__proto__" sur un object ordinaire — affecter une valeur non-object est silencieusement ignoré, et affecter un object modifie le prototype au lieu d'ajouter une clé.
  • C'est une surface d'attaque connue (« prototype pollution »). Un code qui copie des clés non fiables sur un object peut être trompé pour écrire sur __proto__, polluant Object.prototype pour tout le programme.

Les méthodes standardisées sont explicites quant à leur intention : getPrototypeOf/setPrototypeOf modifient le prototype, tandis que les écritures de propriétés ordinaires ne le touchent jamais.

javascript— editable

Objets sans prototype

Object.create(null) crée un object dont le prototype est null. Il n'hérite de rien — pas même de toString, hasOwnProperty, ni de l'accesseur __proto__.

javascript— editable

Le problème de dictionnaire qu'il résout

Un modèle courant consiste à utiliser un object ordinaire comme correspondance entre des clés string et des valeurs. Le problème est qu'un simple {} hérite déjà de clés depuis Object.prototype, donc les clés fournies par l'utilisateur comme "constructor", "toString" ou "__proto__" entrent en collision avec les noms hérités et perturbent les recherches.

javascript— editable

Un object à prototype null n'a pas de clés héritées, donc chaque clé se comporte exactement comme écrite — y compris "__proto__" :

javascript— editable

C'est pourquoi les objets à prototype null constituent des dictionnaires sûrs pour les clés non fiables. (Le Map intégré est un autre bon choix et accepte des clés non-string.)

Ajouter des méthodes à un object à prototype null

Comme il n'y a pas de prototype dont hériter, vous affectez les méthodes directement en tant que propriétés propres.

javascript— editable

Itérer les clés, valeurs et entrées

Object.keys(), Object.values() et Object.entries() retournent des tableaux des propriétés énumérables propres d'un object. De façon cruciale, ils ignorent la chaîne de prototypes, donc ils fonctionnent de façon identique sur les objets normaux et à prototype null. Voir Object.keys, values, entries pour plus de détails.

javascript— editable

Une mise en garde pour les objets à prototype null : ils n'ont pas de toString hérité, donc passer l'un d'eux directement à des littéraux de gabarit ou à String() lève une exception. Itérez avec les utilitaires Object.* (ci-dessus) au lieu de vous fier à la conversion automatique en string.

Vérifier les propriétés propres avec Object.hasOwn()

Pour tester si une clé est une propriété propre de l'object (et non héritée), préférez Object.hasOwn(). C'est le remplacement moderne de obj.hasOwnProperty() et il fonctionne même sur les objets à prototype null, qui n'ont pas du tout de méthode hasOwnProperty.

javascript— editable

Composition avec Object.assign()

Lorsque vous souhaitez qu'un object acquière le comportement de plusieurs autres, la composition est souvent plus claire qu'une seule chaîne d'héritage : un object ne peut avoir qu'un seul prototype, mais Object.assign(target, ...sources) peut intégrer des méthodes de nombreuses sources en copiant leurs propriétés propres et énumérables sur la cible.

javascript— editable

Object.assign() copie également sur un object à prototype null, vous donnant un dictionnaire composé sans surface héritée :

javascript— editable

Mise en garde sur la copie superficielle : Object.assign() copie les valeurs des propriétés, pas des clones profonds. Les valeurs d'object et de tableau sont copiées par référence, donc la source et la cible partagent les mêmes objets imbriqués.

javascript— editable

Pour une copie profonde et indépendante, utilisez plutôt structuredClone(source).

Bonnes pratiques

  • Utilisez les méthodes standardisées, pas __proto__. Préférez Object.create(), Object.getPrototypeOf() et Object.setPrototypeOf(). Traitez __proto__ comme un accesseur hérité à éviter dans votre propre code.
  • Évitez de modifier les prototypes après la création. Définir un prototype choisi au moment de la création avec Object.create(proto) est plus propre et plus facile à raisonner que de le muter ultérieurement avec Object.setPrototypeOf().
  • Utilisez Object.create(null) (ou Map) pour les dictionnaires de clés non fiables. Cela supprime les clés héritées et prévient les surprises de pollution de prototype.
  • Préférez Object.hasOwn() à obj.hasOwnProperty(). C'est plus court, plus sûr à appeler, et fonctionne sur les objets à prototype null.
  • Composez avec Object.assign() lorsque vous avez besoin de comportement de plusieurs sources — souvenez-vous simplement que c'est une copie superficielle.

Pour du matériel connexe, voir Méthodes d'object et « this » et Indicateurs et descripteurs de propriété.

Conclusion

Les méthodes modernes de prototype Object.* vous donnent un contrôle explicite et prévisible sur la chaîne de prototypes, remplaçant l'accesseur capricieux __proto__. Object.create(null) produit un object propre et sans prototype, idéal pour les dictionnaires, tandis que Object.keys/values/entries, Object.hasOwn() et Object.assign() vous permettent d'inspecter et de composer des objets en toute sécurité, quel que soit leur prototype.

Exercices pratiques

Pratique
Quel appel crée un object sans prototype, en faisant un dictionnaire sûr pour des clés arbitraires ?
Quel appel crée un object sans prototype, en faisant un dictionnaire sûr pour des clés arbitraires ?
Was this page helpful?