Javascript 3


Ces exercices sont ceux de la séance : ils sont intercalés dans les slides, juste après le concept qu’ils font travailler. Cette page les rassemble pour que vous puissiez les reprendre à votre rythme.

Chaque notion est vue deux fois : d’abord avec les prototypes (ES5), puis avec la syntaxe class (ES6+). C’est volontaire — les classes ne sont que du sucre par-dessus les prototypes, et vous croiserez encore du code ES5.

La documentation de Javascript est disponible ici ou là.

Exercice 1 — Un User à l'ancienne

Intermédiaire ⏱ 10 min

🎯 Écrire un constructeur et poser ses méthodes sur le prototype.

Créer User(firstname, lastname, age) avec deux méthodes sur le prototype : getFullName() et isAdult().

function User(firstname, lastname, age) {
  // à vous
}

// Les méthodes vont sur User.prototype, pas dans le constructeur

const user = new User("Julien", "Usson", 31)
console.log(user.getFullName()) // "Julien Usson"
console.log(user.isAdult())     // true

Créez un second utilisateur et vérifiez avec === que les deux partagent bien la même fonction getFullName.

Exercice 2 — Hériter à la main

Difficile ⏱ 10 min

🎯 Voir précisément ce que `extends` fera à votre place.

Créer Animal(name) avec speak() → "The animal makes a noise", puis Dog qui en hérite et surcharge speak() → "Rex barks".

function Animal(name) {
  this.name = name
}
Animal.prototype.speak = function () {
  return "The animal makes a noise"
}

function Dog(name) {
  // 1. appeler le constructeur parent
}
// 2. brancher la chaîne de prototypes
// 3. surcharger speak()

console.log(new Animal("Generic").speak()) // "The animal makes a noise"
console.log(new Dog("Rex").speak())        // "Rex barks"

Oubliez volontairement la ligne Dog.prototype.constructor = Dog : que vaut new Dog("Rex").constructor.name ?

Exercice 3 — Le même User, en classe

Facile ⏱ 8 min

🎯 Mesurer ce que la syntaxe `class` fait gagner.

Réécrire l’exercice « Un User à l’ancienne » avec class. Même comportement, mêmes appels.

class User {
  // à vous
}

const user = new User("Julien", "Usson", 31)
console.log(user.getFullName()) // "Julien Usson"
console.log(user.isAdult())     // true

Combien de lignes en moins ? Et vérifiez que getFullName est toujours partagée entre les instances — la classe n’a rien changé au prototype.

Exercice 4 — Hériter avec extends

Facile ⏱ 8 min

🎯 Retrouver le résultat de l'héritage ES5 en trois mots-clés.

Réécrire Animal et Dog avec class, extends et super.

class Animal {
  // à vous
}

class Dog extends Animal {
  // à vous
}

console.log(new Animal("Generic").speak()) // "The animal makes a noise"
console.log(new Dog("Rex").speak())        // "Rex barks"

Essayez d’utiliser this dans le constructeur de Dog avant d’appeler super(). Que dit le message d’erreur ?

Exercice 5 — Le bon speak() au bon moment

Facile ⏱ 5 min

🎯 Constater que la méthode appelée dépend de l'objet, pas du code appelant.

Mettre plusieurs Animal et Dog dans un tableau, le parcourir, appeler speak() sur chacun.

// Reprenez vos classes Animal et Dog

const animals = [/* mélangez des Animal et des Dog */]

for (const animal of animals) {
  console.log(animal.speak())
}

Une seule ligne d’appel, deux comportements : c’est ça, le polymorphisme.

Exercice 6 — Des méthodes sans instance

Facile ⏱ 5 min

🎯 Distinguer ce qui appartient à la classe de ce qui appartient à l'objet.

Créer MathUtils avec deux méthodes statiques : add(a, b) et multiply(a, b).

class MathUtils {
  // à vous
}

console.log(MathUtils.add(1, 2))       // 3
console.log(MathUtils.multiply(6, 7))  // 42

Essayez new MathUtils().add(1, 2). Pourquoi est-ce que ça échoue ?

Exercice 7 — fullName qui se lit et s'écrit

Intermédiaire ⏱ 8 min

🎯 Exposer une propriété calculée comme si c'était un champ.

Créer User avec firstname et lastname, un getter fullName et un setter fullName qui découpe la chaîne reçue.

class User {
  // get fullName() { ... }
  // set fullName(value) { ... }
}

const user = new User("Julien", "Usson")
console.log(user.fullName)     // "Julien Usson"

user.fullName = "Jean Dupont"
console.log(user.firstname)    // "Jean"
console.log(user.lastname)     // "Dupont"

ℹ️ split() découpe la chaîne. Que faire si on reçoit "Jean" tout seul ?

Exercice 8 — Un mot de passe vraiment privé

Intermédiaire ⏱ 8 min

🎯 Empêcher l'extérieur de lire un champ, pas seulement le décourager.

Ajouter à User un champ privé #password, une méthode setPassword(pwd) et une méthode checkPassword(pwd).

class User {
  // #password = ...
}

const user = new User("Julien", "Usson", 31, "mySecretPwd")
console.log(user.checkPassword("wrongPwd"))    // false
console.log(user.checkPassword("mySecretPwd")) // true

user.setPassword("newPwd")
console.log(user.checkPassword("mySecretPwd")) // false
console.log(user.checkPassword("newPwd"))      // true

Essayez console.log(user.#password) depuis l’extérieur, puis console.log(user). Que voyez-vous ?

Exercice 9 — Traduire du vieux code

Difficile ⏱ 12 min

🎯 Relire tout ce qu'on vient de voir, dans les deux syntaxes.

Réécrire ce code ES5 en ES6+ : class, extends, super, static.

function Vehicle(brand, speed) {
  this.brand = brand
  this.speed = speed
}
Vehicle.prototype.accelerate = function (value) { this.speed += value }
Vehicle.prototype.describe = function () {
  return this.brand + " is going at " + this.speed + " km/h"
}
Vehicle.isVehicle = function (obj) { return obj instanceof Vehicle }

function Car(brand, speed, doors) {
  Vehicle.call(this, brand, speed)
  this.doors = doors
}
Car.prototype = Object.create(Vehicle.prototype)
Car.prototype.constructor = Car
Car.prototype.describe = function () {
  return this.brand + " car with " + this.doors + " doors going at " + this.speed + " km/h"
}

Vérifiez que Vehicle.isVehicle(new Car("Renault", 90, 5)) vaut toujours true.

Exercice 10 — Mini-projet — un combat

Difficile ⏱ 30 min

🎯 Assembler classes, héritage, champs privés et méthodes statiques.

Player : name, level, et des hp non modifiables de l’extérieur. Méthodes attack(), takeDamage(amount), isAlive().

Warrior extends Player : une strength en plus, attack() surchargée en "Warrior attacks with strength X", et des dégâts supérieurs.

Player.compare(a, b) — statique : retourne le joueur du niveau le plus élevé, ou null en cas d’égalité.

Puis un script qui crée deux joueurs, les fait s’attaquer à tour de rôle, s’arrête quand l’un meurt et affiche le vainqueur.

Warrior attacks with strength 10
Player takes 10 damage
Player HP: 0
Player is dead
Winner is Conan

🎁 Pour aller plus loin : une classe Mage, des armes, de l’équipement qui réduit les dégâts reçus.