pinterest linkedin behance copy arrow-up
QZY.codes by quazerty

De quoi avez vous besoin ?

Quazerty

Bootstrap 5.2

JavaScript

PHP

Nos plateformes

Quadevis

VegetGarden

Classes

Les classes sont un modèle pour créer des objets. Ils encapsulent les données avec du code pour travailler sur ces données. Les classes en JS sont construites sur des prototypes mais ont également une syntaxe et une sémantique propres aux classes.

Pour plus d'exemples et d'explications, consultez le guide Utilisation des classes.

Description


Définir des classes

Les classes sont en fait des « fonctions spéciales », et tout comme vous pouvez définir des expressions de fonction et des déclarations de fonction, une classe peut être définie de deux manières : une expression de classe ou une déclaration de classe.


// Declaration
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

// Expression; the class is anonymous but assigned to a variable
const Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

// Expression; the class has its own name
const Rectangle = class Rectangle2 {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

Comme les expressions de fonction, les expressions de classe peuvent être anonymes ou avoir un nom différent de la variable à laquelle elles sont affectées. Cependant, contrairement aux déclarations de fonction, les déclarations de classe ont les mêmes restrictions de zone morte temporelle que let ou const et se comportent comme si elles n'étaient pas levées.

Corps de classe

Le corps d'une classe est la partie qui se trouve entre accolades {}. C'est ici que vous définissez les membres de la classe, tels que les méthodes ou le constructeur.

Le corps d'une classe est exécuté en mode strict même sans la directive "use strict".

Un élément de classe peut être caractérisé par trois aspects :

  • Kind : Getter, setter, méthode ou champ
  • Emplacement : statique ou instance
  • Visibilité : Publique ou privée

Ensemble, ils totalisent jusqu'à 16 combinaisons possibles. Pour diviser la référence de manière plus logique et éviter les chevauchements de contenu, les différents éléments sont présentés en détail dans différentes pages :

Définitions des méthodes
Méthode d'instance publique

getter
Getter d'instance publique

setter
Paramétreur d'instance publique

Champs de classe publique
Champ d'instance publique

statique
Méthode statique publique, getter, setter et champ

Fonctionnalités de classe privée
Tout ce qui est privé

Note :
Les fonctionnalités privées ont la restriction que tous les noms de propriété déclarés dans la même classe doivent être uniques. Toutes les autres propriétés publiques ne sont pas soumises à cette restriction : vous pouvez avoir plusieurs propriétés publiques portant le même nom et la dernière écrase les autres. C'est le même comportement que dans les initialiseurs d'objets.

De plus, il existe deux syntaxes d'éléments de classe spéciales : les blocs constructeur et d'initialisation statique, avec leurs propres références.

Constructor

La méthode constructeur est une méthode spéciale pour créer et initialiser un objet créé avec une classe. Il ne peut y avoir qu'une seule méthode spéciale portant le nom « constructeur » dans une classe — une SyntaxError est levée si la classe contient plus d'une occurrence d'une méthode constructeur.

Un constructeur peut utiliser le mot-clé super pour appeler le constructeur de la super classe.

Vous pouvez créer des propriétés d'instance dans le constructeur :


class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Alternativement, si les valeurs des propriétés de votre instance ne dépendent pas des arguments du constructeur, vous pouvez les définir en tant que champs de classe.

Blocs d'initialisation statiques

Les blocs d'initialisation statiques permettent une initialisation flexible des propriétés statiques, y compris l'évaluation des instructions lors de l'initialisation, tout en accordant l'accès à la portée privée.

Plusieurs blocs statiques peuvent être déclarés, et ceux-ci peuvent être entrelacés avec la déclaration des champs et méthodes statiques (tous les éléments statiques sont évalués dans l'ordre de déclaration).

Méthodes

Les méthodes sont définies sur le prototype de chaque instance de classe et sont partagées par toutes les instances. Les méthodes peuvent être des fonctions simples, des fonctions asynchrones, des fonctions de générateur ou des fonctions de générateur asynchrone. Pour plus d'informations, consultez les définitions de méthodes.


class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width;
  }
  *getSides() {
    yield this.height;
    yield this.width;
    yield this.height;
    yield this.width;
  }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100
console.log([...square.getSides()]); // [10, 10, 10, 10]
Méthodes et champs statiques

Le mot clé static définit une méthode ou un champ statique pour une classe. Les propriétés statiques (champs et méthodes) sont définies sur la classe elle-même plutôt que sur chaque instance. Les méthodes statiques sont souvent utilisées pour créer des fonctions utilitaires pour une application, tandis que les champs statiques sont utiles pour les caches, la configuration fixe ou toute autre donnée qui n'a pas besoin d'être répliquée entre les instances.


class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static displayName = "Point";
  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; // undefined
p1.distance; // undefined
p2.displayName; // undefined
p2.distance; // undefined

console.log(Point.displayName); // "Point"
console.log(Point.distance(p1, p2)); // 7.0710678118654755
Déclarations de champs

Avec la syntaxe de déclaration de champ de classe, l'exemple de constructeur peut être écrit comme suit


class Rectangle {
  height = 0;
  width;
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Les champs de classe sont similaires aux propriétés des objets, pas aux variables, nous n'utilisons donc pas de mots-clés tels que const pour les déclarer. En JavaScript, les fonctionnalités privées utilisent une syntaxe d'identification spéciale, donc les mots-clés modificateurs tels que public et private ne doivent pas non plus être utilisés.

Comme vu ci-dessus, les champs peuvent être déclarés avec ou sans valeur par défaut. Les champs sans valeurs par défaut sont par défaut non définis. En déclarant les champs à l'avance, les définitions de classe deviennent plus auto-documentées et les champs sont toujours présents, ce qui facilite les optimisations.

Voir les champs de classe publique pour plus d'informations.

Fonctionnalités de classe privée

En utilisant des champs privés, la définition peut être affinée comme ci-dessous.


class Rectangle {
  #height = 0;
  #width;
  constructor(height, width) {
    this.#height = height;
    this.#width = width;
  }
}

C'est une erreur de référencer des champs privés depuis l'extérieur de la classe ; ils ne peuvent être lus ou écrits que dans le corps de la classe. En définissant des éléments qui ne sont pas visibles en dehors de la classe, vous garantissez que les utilisateurs de vos classes ne peuvent pas dépendre de composants internes, qui peuvent changer d'une version à l'autre.

Les champs privés ne peuvent être déclarés qu'à l'avance dans une déclaration de champ. Ils ne peuvent pas être créés ultérieurement en leur attribuant, comme le peuvent les propriétés normales.

Pour plus d'informations, consultez les fonctionnalités des classes privées.

Héritage

Le mot-clé extends est utilisé dans les déclarations de classe ou les expressions de classe pour créer une classe en tant qu'enfant d'un autre constructeur (soit une classe, soit une fonction).


class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // call the super class constructor and pass in the name parameter
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}

const d = new Dog("Mitzie");
d.speak(); // Mitzie barks.

S'il y a un constructeur présent dans la sous-classe, il doit d'abord appeler super() avant de l'utiliser. Le mot-clé super peut également être utilisé pour appeler les méthodes correspondantes de la super classe.


class Cat {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(`${this.name} roars.`);
  }
}

const l = new Lion("Fuzzy");
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.
Ordre d'évaluation

Lorsqu'une déclaration de classe ou une expression de classe est évaluée, ses différents composants sont évalués dans l'ordre suivant :

  1. La clause extends, si elle est présente, est d'abord évaluée. Il doit être évalué comme une fonction constructeur valide ou null, sinon une TypeError est levée.
  2. La méthode constructeur est extraite, remplacée par une implémentation par défaut si le constructeur n'est pas présent. Cependant, comme la définition du constructeur n'est qu'une définition de méthode, cette étape n'est pas observable.
  3. Les clés de propriété des éléments de classe sont évaluées dans l'ordre de déclaration. Si la clé de propriété est calculée, l'expression calculée est évaluée, avec la valeur this définie sur la valeur this entourant la classe (et non sur la classe elle-même). Aucune des valeurs de propriété n'est encore évaluée.
  4. Les méthodes et accesseurs sont installés dans l'ordre de déclaration. Les méthodes d'instance et les accesseurs sont installés sur la propriété prototype de la classe actuelle, et les méthodes statiques et les accesseurs sont installés sur la classe elle-même. Les méthodes et accesseurs d'instance privée sont enregistrés pour être installés directement sur l'instance ultérieurement. Cette étape n'est pas observable.
  5. La classe est maintenant initialisée avec le prototype spécifié par extends et l'implémentation spécifiée par le constructeur. Pour toutes les étapes ci-dessus, si une expression évaluée tente d'accéder au nom de la classe, une ReferenceError est levée car la classe n'est pas encore initialisée.
  6. Les valeurs des éléments de classe sont évaluées dans l'ordre de déclaration :
    • Pour chaque champ d'instance (public ou privé), son expression d'initialisation est enregistrée. L'initialiseur est évalué lors de la création de l'instance, au début du constructeur (pour les classes de base) ou immédiatement avant le retour de l'appel super() (pour les classes dérivées).
    • Pour chaque champ statique (public ou privé), son initialiseur est évalué avec cet ensemble sur la classe elle-même, et la propriété est créée sur la classe.
    • Les blocs d'initialisation statiques sont évalués avec cet ensemble sur la classe elle-même.
  7. La classe est maintenant entièrement initialisée et peut être utilisée comme fonction constructeur.

Pour savoir comment les instances sont créées, consultez la référence du constructeur.

Exemples


Lier cela avec des méthodes d'instance et statiques

Lorsqu'une méthode statique ou d'instance est appelée sans valeur pour cela, par exemple en attribuant la méthode à une variable puis en l'appelant, cette valeur ne sera pas définie dans la méthode. Ce comportement est le même même si la directive "use strict" n'est pas présente, car le code dans le corps de la classe est toujours exécuté en mode strict.


class Animal {
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

const obj = new Animal();
obj.speak(); // the Animal object
const speak = obj.speak;
speak(); // undefined

Animal.eat(); // class Animal
const eat = Animal.eat;
eat(); // undefined

Si nous réécrivons ce qui précède en utilisant la syntaxe traditionnelle basée sur les fonctions en mode non strict, alors ces appels de méthode sont automatiquement liés à globalThis. En mode strict, la valeur de this reste indéfinie.


function Animal() {}

Animal.prototype.speak = function () {
  return this;
};

Animal.eat = function () {
  return this;
};

const obj = new Animal();
const speak = obj.speak;
speak(); // global object (in non–strict mode)

const eat = Animal.eat;
eat(); // global object (in non-strict mode)

Spécifications


ECMAScript Language Specification
# sec-class-definitions

Compatibilité du navigateur


Report problems with this compatibility data on GitHub

Voir aussi


© 2010-2024 Quazerty.