Class extends Object ?
Comme nous le savons, tous les objets héritent normalement de Object.prototype
et ont accès à des méthodes d’objet “génériques” comme hasOwnProperty
etc.
Par exemple :
class Rabbit {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
// la méthode hasOwnProperty provient de Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true
Mais si nous l’épelons explicitement comme suit : "class Rabbit extends Object"
, le résultat serait alors différent d´un simple "class Rabbit"
?
Quelle est la différence ?
Voici un exemple d’un tel code (cela ne fonctionne pas – pourquoi ? Réparez le ?) :
class Rabbit extends Object {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // Error
Voyons d’abord pourquoi ce dernier code ne fonctionne pas.
La raison devient évidente si nous essayons de l’exécuter. Un constructeur de classe héritant doit appeler super()
. Sinon "this"
ne sera pas “défini”.
Alors, voici la solution :
class Rabbit extends Object {
constructor(name) {
super(); // besoin d'appeler le constructeur parent lors de l'héritage
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
Mais ce n’est pas tout.
Même après le correctif, il existe toujours une différence importante entre "class Rabbit extends Object"
et class Rabbit
.
Comme on le sait, la syntaxe “extends” configure deux prototypes :
- Entre le
"prototype"
des fonctions du constructeur (pour les méthodes). - Entre les fonctions constructeur elles-mêmes (pour les méthodes statiques).
Dans notre cas, pour class Rabbit extends Object
, cela signifie :
class Rabbit extends Object {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
Donc Rabbit
donne maintenant accès aux méthodes statiques de Object
via Rabbit
, comme ceci :
class Rabbit extends Object {}
// normalement nous appelons Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
Mais si nous n’avons pas extends Object
, alors Rabbit.__proto__
n’est pas défini sur Object
.
Voici la démo :
class Rabbit {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // comme toute fonction par défaut
// error, no such function in Rabbit
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
Donc, Rabbit
ne donne pas accès aux méthodes statiques de Object
dans ce cas.
En passant, Function.prototype
a des méthodes de fonction “génériques”, comme call
, bind
, etc. Elles sont finalement disponibles dans les deux cas, car pour le constructeur Object
intégré, Object.__proto__ === Function.prototype
.
Voici l’image :
Donc, pour faire court, il y a deux différences :
class Rabbit | class Rabbit extends Object |
---|---|
– | doit appeler super() dans le constructeur |
Rabbit.__proto__ === Function.prototype |
Rabbit.__proto__ === Object |