Un jour, Guido a dit que Modern JavaScript for the Impatient était un bon livre.
Comme tout ce que dit Guido est vrai, j'ai donc acheté ce livre. Mieux, j'ai même commencé à le lire.
Et c'est vrai que le livre est bon.
Mais contrairement à ce que laisse penser son titre, il vaut mieux être patient si vous décidez de faire les exercices.
C'est d'ailleurs un exercice du chapitre 4 qui m'a donné une idée :
Draw a diagram of
SavingAccount
andCheckingAccount
objects from the preceding exercice, similar to Figure 4-4.
La représentation visuelle aide beaucoup et je me suis dit que serait sympa de pousser le périmètre du diagramme pour illustrer en même temps le billet "Héritage et classes en JavaScript" et montrer toute la chaîne des prototypes.
Vous trouverez le diagramme juste après le code.
Le code
class BankAccount {
constructor(balance = 0) {
this.balance = balance
}
get balanceInt() { return Math.floor(this.balance) }
}
class SavingsAccount extends BankAccount {
constructor(balance = 0, interest = 5) {
super(balance)
this.interest = interest
}
addInterest() {
this.balance *= 1 + this.interest / 100
}
}
class CheckingAccount extends SavingsAccount {
constructor(balance = 0, interest = 5, fee = 5) {
super(balance, interest)
this.fee = fee
}
withdraw(amount) {
console.log(`Withdrawing an amount of ${amount}. Cost is ${this.fee}.`)
const amountToWithdraw = amount + this.fee
this.balance -= amountToWithdraw
}
}
const account1 = new CheckingAccount(100, 10, 2)
const account2 = new CheckingAccount(50, 4, 5)
Diagramme de la chaîne des prototypes
JavaScript n'a pas vraiment de système de classe.
À la place, on utilise l'opérateur new
avec des fonctions qu'on appelle alors "fonctions constructrices" (new.target
peut être utilisé pour forcer l'utilisation de new
).
La syntaxe avec class
et extends
dans le code ci-dessus est un sucre syntaxique pour créer des fonctions constructrices.
Toute fonction en JavaScript a une propriété prototype
qui pointe vers un objet prototype
créé automatiquement. On peut y stocker des méthodes et des propriétés.
Une fonction constructrice produit des objets qui partagent son objet prototype
.
Les prototypes sont chaînables.
Si aucun résultat n'est trouvé, une recherche est effectuée dans la chaîne des prototypes. Cette recherche ne fonctionne qu'en lecture. En écriture, la valeur est toujours mise à jour dans l'objet lui-même !
Le diagramme ci-dessous représente la chaîne des prototypes avec les fonctions constructrices à gauche :
Afficher la chaîne des prototypes
function printPrototypeChainOf(obj) {
let proto = Object.getPrototypeOf(obj)
let result = ''
while (proto) {
if (result) {
result += ' => '
}
if (typeof proto === 'function' && proto.name) {
result += `${proto.name}`
} else {
// This could be an object or `Function.prototype` or `Object.prototype`.
result += `${proto.constructor.name}.prototype`
}
proto = Object.getPrototypeOf(proto)
}
console.log(result)
}
printPrototypeChainOf(account1)
// CheckingAccount.prototype => SavingsAccount.prototype => BankAccount.prototype => Object.prototype
printPrototypeChainOf(account2)
// CheckingAccount.prototype => SavingsAccount.prototype => BankAccount.prototype => Object.prototype
printPrototypeChainOf(CheckingAccount)
// SavingsAccount => BankAccount => Function.prototype => Object.prototype