Les classes intégrées telles que Array, Map et autres sont également extensibles.
Par exemple, ici, PowerArray
hérite du Array
natif :
// ajoutez-y une méthode supplémentaire
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
}
}
let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false
let filteredArr = arr.filter(item => item >= 10);
alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false
Notez une chose très intéressante. Les méthodes intégrées telles que filter
, map
et autres renvoient des nouveaux objets exactement du type hérité PowerArray
. Leur implémentation interne utilise la propriété d’objet constructor
pour cela.
Dans l’exemple ci-dessus,
arr.constructor === PowerArray
Lorsque arr.filter()
est appelé, elle crée en interne le nouveau tableau de résultats en utilisant exactement arr.constructor
, et non pas Array
. C’est en fait très intéressant, car nous pouvons continuer à utiliser les méthodes PowerArray
sur le résultat.
Encore plus, nous pouvons personnaliser ce comportement.
Nous pouvons ajouter un accésseur statique spécial Symbol.species
à la classe. S’il existe, il devrait renvoyer le constructeur que JavaScript utilisera en interne pour créer de nouvelles entités dans map
, filter
, etc.
Si nous souhaitons que des méthodes intégrées comme map
ou filter
renvoient des tableaux classiques, nous pouvons retourner Array
dans Symbol.species
, comme ici :
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
}
// les méthodes intégrées l'utiliseront comme constructeur
static get [Symbol.species]() {
return Array;
}
}
let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false
// filter crée un nouveau tableau en utilisant arr.constructor [Symbol.species] comme constructeur
let filteredArr = arr.filter(item => item >= 10);
// filteredArr n'est pas un PowerArray, mais un Array
alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
Comme vous pouvez le constater, maintenant, .filter
renvoie Array
. La fonctionnalité étendue n’est donc plus transmise.
D’autres collections, telles que Map
et Set
, fonctionnent de la même manière. Ils utilisent également Symbol.species
.
Pas d’héritage statique dans les éléments intégrés
Les objets intégrés ont leurs propres méthodes statiques, par exemple Object.keys
, Array.isArray
, etc.
Comme nous le savons déjà, les classes natives s’étendent les uns des autres. Par exemple, Array
étend (hérite de) Object
.
Normalement, lorsqu’une classe en étend une autre, les méthodes statiques et non statiques sont héritées. Cela a été expliqué en détail dans le chapitre Propriétés et méthodes statiques.
Mais les classes intégrées sont une exception. Elles n’héritent pas des méthodes statiques les unes des autres.
Par exemple, Array
et Date
héritent de Object
, de sorte que leurs instances ont des méthodes issues de Object.prototype
. Mais Array.[[Prototype]]
ne fait pas référence à Object
, il n’y a donc pas, par exemple, de méthode statique Array.keys()
(ou Date.keys()
).
Voici le schéma la structure pour Date
et Object
:
Comme vous pouvez le constater, il n’y a pas de lien entre Date
et Object
. Ils sont indépendants, seul Date.prototype
hérite de Object.prototype
.
C’est une différence d’héritage importante entre les objets intégrés par rapport à ce que nous obtenons avec extends
.