Précédent La playlist City Pop

Héritage et classes en JavaScript (bis)

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 and CheckingAccount 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

L'important c'est l'héritage :

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)

La syntaxe à base du mot class est trompeuse car JavaScript n'a pas de système de classe. Il y a juste des "fonctions constructeur" qui produisent des objets partageant des prototypes. Ça n'est pas très important en pratique mais c'est bien de le savoir.

Le diagramme

Héritage et classes en JavaScript

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

Conclusion

C'était vraiment très intéressant.