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

Object : méthode statique setPrototypeOf()

Baseline
Large disponibilité

Cette fonctionnalité est bien établie et fonctionne sur de nombreux appareils et versions de navigateurs. Elle est disponible sur tous les navigateurs depuis septembre 2015.

La méthode statique Object.setPrototypeOf() définit le prototype (c'est-à-dire la propriété [[Prototype]] interne) de l'objet défini par un autre objet ou null.

Attention : Changer le [[Prototype]] d'un objet est, par la nature des moteurs JavaScript modernes et la façon dont ils optimisent les accès aux propriétés, actuellement une opération très lente dans tous les navigateurs et moteurs JavaScript. De plus, les effets de la modification de l'héritage sont subtils et étendus, et ne se limitent pas au temps passé dans l'instruction Object.setPrototypeOf(...), mais peuvent s'étendre à tout code ayant accès à un objet dont le [[Prototype]] a été modifié. Vous pouvez en lire davantage dans Fondamentaux des moteurs JavaScript : optimisation des prototypes (angl.).

Parce que cette fonctionnalité fait partie du langage, il incombe toujours aux développeur·euse·s de moteurs de l'implémenter de manière performante (idéalement). Jusqu'à ce que les développeur·euse·s de moteurs résolvent ce problème, si vous vous souciez des performances, vous devez éviter de définir le [[Prototype]] d'un objet. À la place, créez un nouvel objet avec le [[Prototype]] souhaité en utilisant Object.create().

Exemple interactif

const obj = {};
const parent = { toto: "truc" };

console.log(obj.toto);
// Résultat attendu : undefined

Object.setPrototypeOf(obj, parent);

console.log(obj.toto);
// Résultat attendu : "truc"

Syntaxe

js
Object.setPrototypeOf(obj, prototype)

Paramètres

obj

L'objet dont on souhaite définir le prototype.

prototype

Le nouveau prototype de l'objet (un objet ou null).

Valeur de retour

L'objet défini.

Exceptions

TypeError

Une exception est levée dans l'un des cas suivants :

  • Le paramètres obj est undefined ou null.
  • Le paramètre obj n'est pas extensible, ou c'est un objet exotique à prototype immuable (angl.), tel que Object.prototype ou window. Cependant, l'erreur n'est pas levée si le nouveau prototype est la même valeur que le prototype original de obj.
  • Le paramètre prototype n'est pas un objet ou null.

Description

Object.setPrototypeOf() est généralement considéré comme la manière appropriée de définir le prototype d'un objet. Vous devez toujours l'utiliser plutôt que l'accesseur obsolète Object.prototype.__proto__.

Si le paramètre obj n'est pas un objet (par exemple, un nombre, une chaîne de caractères, etc.), cette méthode ne fait rien — sans le convertir en objet ni tenter de définir son prototype — et retourne directement obj en tant que valeur primitive. Si prototype a la même valeur que le prototype de obj, alors obj est directement retourné, sans provoquer de TypeError même lorsque obj a un prototype immuable.

Pour des raisons de sécurité, certains objets intégrés sont conçus pour avoir un prototype immuable. Cela empêche les attaques de pollution de prototype, en particulier celles liées aux [mandataires]((https://github.com/tc39/ecma262/issues/272). Le langage de base ne définit que Object.prototype comme un objet exotique à prototype immuable, dont le prototype est toujours null. Dans les navigateurs, window et location sont deux autres exemples très courants.

js
Object.isExtensible(Object.prototype); // true ; vous pouvez ajouter plus de propriétés
Object.setPrototypeOf(Object.prototype, {}); // TypeError: Impossible de définir le prototype de l'objet exotique à prototype immuable '#<Object>'
Object.setPrototypeOf(Object.prototype, null); // Pas d'erreur ; le prototype de `Object.prototype` est déjà `null`

Exemples

Héritage pseudo-classique utilisant Object.setPrototypeOf()

L'héritage en JS utilisant les classes.

js
class Humain {}
class SuperHero extends Humain {}

const superMan = new SuperHero();

Cependant, si nous voulons implémenter des sous-classes sans utiliser class, nous pouvons faire ce qui suit :

js
function Humain(nom, niveau) {
  this.nom = nom;
  this.niveau = niveau;
}

function SuperHero(nom, niveau) {
  Humain.call(this, nom, niveau);
}

Object.setPrototypeOf(SuperHero.prototype, Humain.prototype);

// Définit le `[[Prototype]]` de `SuperHero.prototype`
// à `Humain.prototype`
// Pour définir la chaîne d'héritage de prototype

Humain.prototype.parler = function () {
  return `${this.nom} dit bonjour.`;
};

SuperHero.prototype.voler = function () {
  return `${this.nom} est en train de voler.`;
};

const superMan = new SuperHero("Clark Kent", 1);

console.log(superMan.voler());
console.log(superMan.parler());

La similitude entre l'héritage classique (avec les classes) et l'héritage pseudo-classique (avec la propriété prototype des constructeurs) comme montré ci-dessus est mentionnée dans Chaînes d'héritage.

Comme la propriété prototype des constructeurs de fonctions est modifiable, vous pouvez la réaffecter à un nouvel objet créé avec Object.create() pour obtenir la même chaîne d'héritage. Il y a des points auxquels il faut faire attention lors de l'utilisation de create(), comme se rappeler de ré-ajouter la propriété constructor.

Dans l'exemple ci-dessous, qui utilise également des classes, SuperHero est fait pour hériter de Humain sans utiliser extends en utilisant setPrototypeOf() à la place.

Attention : Il n'est pas conseillé d'utiliser setPrototypeOf() à la place de extends pour des raisons de performance et de lisibilité.

js
class Humain {}
class SuperHero {}

// Définit les propriétés d'instance
Object.setPrototypeOf(SuperHero.prototype, Humain.prototype);

// Définit les propriétés statiques
Object.setPrototypeOf(SuperHero, Humain);

const superMan = new SuperHero();

L'héritage sans extends est mentionné dans le sous-classement ES-6 (angl.).

Spécifications

Spécification
ECMAScript® 2027 Language Specification
# sec-object.setprototypeof

Compatibilité des navigateurs

Voir aussi