TW3 — Technologies du Web 3

Prototypes et classes

Chaîne de prototypes, classes ES6, héritage, Object.* et bonnes pratiques this.

JavaScript est un langage prototype-based : chaque objet a un lien vers un autre objet (son prototype) dont il hérite des propriétés. La syntaxe class (ES6) est du sucre syntaxique au-dessus de ce mécanisme. Comprendre les prototypes explique pourquoi instanceof, this et l'héritage fonctionnent comme ils le font.

🔗 La chaîne de prototypes

Chaque objet JavaScript possède un lien interne vers un autre objet, accessible via Object.getPrototypeOf(obj) (ou historiquement __proto__). Quand on accède à une propriété manquante sur l'objet, JavaScript remonte la chaîne jusqu'à trouver la propriété ou atteindre null.

const animal = { parler() { console.log("...") } }
const chien = Object.create(animal)
chien.race = "Labrador"

chien.race      // "Labrador" — propre à chien
chien.parler()  // "..." — hérité du prototype animal
chien.toString  // hérité de Object.prototype (tout en bas de la chaîne)

Visualizing la chaîne

chien  ──>  animal  ──>  Object.prototype  ──>  null

Méthodes utiles pour inspecter :

Object.getPrototypeOf(chien) === animal  // true
chien instanceof Object                  // true (remonte jusqu'à Object.prototype)
Object.prototype.isPrototypeOf(chien)   // true

Constructeur et .prototype

function Personne(nom) {
  this.nom = nom
}

Personne.prototype.sePresenter = function() {
  console.log(`Je m'appelle ${this.nom}`)
}

const alice = new Personne("Alice")
alice.sePresenter()         // "Je m'appelle Alice"
alice instanceof Personne  // true

La propriété .prototype de la fonction constructeur est l'objet qui devient le prototype de chaque instance créée avec new. Ce n'est pas le prototype de la fonction elle-même (Personne.__proto__ est Function.prototype).

.prototype ≠ __proto__

Personne.prototype est le prototype des instances (alice.__proto__ === Personne.prototype). Personne.__proto__ est le prototype de la fonction elle-même (Function.prototype). Confondre les deux est une source fréquente de bugs.

🏷️ Classes ES6

La syntaxe class est plus lisible mais fonctionne exactement sur le même mécanisme prototype.

class Animal {
  constructor(espece) {
    this.espece = espece
  }

  identifier() {
    return `Je suis un ${this.espece}`
  }

  // Méthode statique — appelée sur la classe, pas l'instance
  static compter() {
    return Animal.count++
  }
}

class Chien extends Animal {
  constructor(race) {
    super("Chien")   // appelle Animal constructor
    this.race = race
  }

  identifier() {
    return `${this.race} (${super.identifier()})`
  }
}

const milou = new Chien("Terry")
milou.identifier()  // "Terry (Je suis un Chien)"
Chien.compter()    // appel statique

Points clés à retenir

  • super() doit être appelé avant this dans le constructeur d'une sous-classe
  • Les méthodes de classe sont ajoutées sur Classname.prototype (pas sur l'instance)
  • Les méthodes static sont sur la classe elle-même (Classname.nom)
  • Les getters/setters fonctionnent avec get nom() / set nom(val)
class User {
  constructor(nom) {
    this._nom = nom
  }

  get nom() {
    return this._nom.trim()
  }

  set nom(valeur) {
    if (!valeur) throw new Error("Nom vide")
    this._nom = valeur
  }
}

Champs privés (ES2022+)

class Compte {
  #solde = 0

  crediter(montant) {
    this.#solde += montant
  }

  getSolde() {
    return this.#solde
  }
}

Les champs privés (#nom) sont réellement inaccessibles hors de la classe — plus fort que la convention _nom (qui n'empêche que l'accès accidentel).

🧰 Méthodes utilitaires Object

Object expose de nombreuses méthodes pour inspecter et manipuler des objets sans les modifier ou en créant de nouveaux.

Inspection

Object.keys(obj)    // tableau des clés énumérables propres
Object.values(obj)  // tableau des valeurs correspondantes
Object.entries(obj) // tableau de [clé, valeur]
Object.hasOwn(obj, key)  // true si la clé est propre (sans remonter la chaîne)
obj.hasOwnProperty(key)  // ancienne forme (peut être falsifié)
const user = { nom: "Alice", age: 25 }
Object.entries(user)
// [["nom", "Alice"], ["age", 25]]

Création et manipulation

Object.assign(cible, source1, source2)  // copie les clés énumérables (shallow copy)
Object.create(proto)                    // nouvel objet avec prototype donné
Object.defineProperty(obj, key, descriptor)  // contrôle fin : enumerable, writable, configurable
Object.freeze(obj)                      // empêche modification / ajout / suppression
Object.seal(obj)                        // empêche ajout / suppression, permet modification existante

assign est une copie shallow

Object.assign({}, obj) ne clone pas les objets imbriqués — il copie la référence. { ...obj } fait la même chose. Pour un clone profond, utiliser structuredClone(obj) (navigateur/Node moderne) ou une librairie dédiée.

Comparaison : Object.keys vs for…in

const parent = { heritage: true }
const enfant = Object.create(parent)
enfant.propre = "valeur"

Object.keys(enfant)     // ["propre"] — uniquement les clés propres
for (const k in enfant) // "propre", "heritage" — remonte la chaîne

Utiliser Object.keys() quand on veut uniquement les propriétés directes de l'objet. Utiliser for…in (avec hasOwnProperty pour filtrer) si on veut inspecter la totalité de la chaîne de prototypes.

for…in sans hasOwnProperty

for (const k in obj) inclut les propriétés héritées de la chaîne prototype. Sans obj.hasOwnProperty(k), on risque de traiter des méthodes natives (toString, valueOf…) comme des données. Préférer Object.keys() pour les données.

🛠️ Exercices pratiques

Classes et héritage — Animal, Chien, Object.keys

Comprendre la chaîne de prototypes et les classes ES6

Vous allez créer des classes, implémenter l'héritage avec extends et super, utiliser une méthode statique et comparer Object.keys vs for...in.

  • Définir une classe avec constructeur et méthode
  • Implémenter l'héritage avec extends et super
  • Ajouter une méthode statique avec compteur
  • Comparer Object.keys vs for...in (propriétés propres vs héritées)

Partie A — Classe Animal

Créez une classe Animal avec :

  • un constructeur (espece) initialisant this.espece
  • une méthode identifier() qui retourne "Je suis un [espece]"

Indice — Constructeur et méthode

Le constructeur est défini avec constructor(espece) { this.espece = espece }. Les méthodes sont définies directement dans le corps de la classe (pas de function keyword).

Partie B — Héritage avec Chien extends Animal

Créez une classe Chien extends Animal avec :

  • un constructeur (race) qui appelle super("Chien") et stocke this.race
  • une méthode identifier() qui retourne "[race] — Je suis un Chien"

Indice — super()

super("Chien") doit être appelé AVANT d'utiliser this. La méthode identifier() peut appeler super.identifier() si elle veut réutiliser la version parente.

Partie C — Méthode statique compter()

Ajoutez une méthode statique compter() sur Chien :

  • propriété statique count incrémentée à chaque instanciation
  • compter() retourne le nombre de chiens créés

Indice — Static

Déclarez static count = 0 dans le corps de la classe. Dans le constructeur, incrémentez Chien.count++. La méthode static compter() retourne Chien.count.

Partie D — Object.keys vs for…in

Créez un objet enfant avec 1 propriété propre et un prototype hérité. Vérifiez que Object.keys(enfant) ne retourne que la propriété propre, contrairement à for...in qui remonte la chaîne.

Indice — Object.create

Object.create(parent) crée un objet dont le prototype est parent. Ajoutez une propriété avec enfant.propre = "valeur". Object.keys() ne retourne que les propriétés propres ; for...in inclut les héritées.

Code à valider

javascript

🧩 Synthèse du bloc

Chaîne de prototypes

Chaque objet a un prototype ; l'accès à une propriété remonte la chaîne jusqu'à null. Object.create et new le contrôlent.

Classes ES6

Sucre syntaxique sur les prototypes. extends, super, static, getters/setters, champs privés #.

Object.*

keys/values/entries pour inspecter, assign pour copier (shallow), freeze/seal pour contrôler la mutabilité.

this et instanceof

this dépend de la façon dont la fonction est appelée. instanceof remonte la chaîne prototype pour tester.

Quiz de fin de bloc

Quiz du chapitre

2 questions
0 / 2 répondue0%
  1. 1Comment itérer sur les clés d'un objet ?
  2. 2Que signifie 'this' dans une méthode d'objet classique ?
Répondez à toutes les questions pour valider.

JavaScript avancé

Terminez le quiz du chapitre pour le marquer comme complété.

Tableau de bord

On this page