l’héritage de Classe est un moyen pour une classe d’étendre une autre classe.

afin que nous puissions créer de nouvelles fonctionnalités au-dessus de l’existant.

Le « extends” mot-clé

disons que nous avons la classe Animal:

Voici comment nous pouvons représenter animal objet et Animal de classe graphiquement:

…Et nous aimerions créer un autre class Rabbit.,

comme les lapins sont des animaux,Rabbit la classe doit être basée surAnimal, avoir accès aux méthodes animales, afin que les lapins puissent faire ce que les animaux « génériques” peuvent faire.

La syntaxe pour étendre une autre classe est: class Child extends Parent.

nous allons créer class Rabbit qui hérite de Animal:

l’Objet de la Rabbit de classe ont accès à la fois à l’ Rabbit méthodes, telles que le rabbit.hide(), et aussi Animal méthodes, telles que le rabbit.run().,

en interne, le mot-cléextends fonctionne en utilisant la bonne vieille mécanique de prototype. Il définit Rabbit.prototype.] de Animal.prototype. Donc, si une méthode n’est pas trouvée dans Rabbit.prototype, JavaScript prend de la Animal.prototype.,

par exemple, pour trouver la méthode rabbit.run, le moteur vérifie (de bas en haut sur l’image):

comme nous pouvons le rappeler dans le chapitre prototypes natifs, JavaScript lui-même utilise l’héritage prototypique pour les objets intégrés. E. g. Date.prototype.] est Object.prototype. C’est pourquoi les dates ont accès à des méthodes d’objet génériques.,

Tout l’expression est permise après extends

Classe syntaxe permet de spécifier non seulement une classe, mais de toute expression après extends.

Par exemple, un appel de fonction qui génère la classe parent:

function f(phrase) { return class { sayHi() { alert(phrase); } };}class User extends f("Hello") {}new User().sayHi(); // Hello

Ici class User hérite de la suite de f("Hello").,

cela peut être utile pour les modèles de programmation avancés lorsque nous utilisons des fonctions pour générer des classes en fonction de nombreuses conditions et pouvons en hériter.

remplacement d’une méthode

Maintenant, nous allons aller de l’avant et de remplacer une méthode. Par défaut, toutes les méthodes qui ne sont pas spécifiées dans class Rabbit sont prises directement « telles quelles” à partir de class Animal.,

Mais si l’on précise notre propre méthode dans Rabbit, stop() ensuite, il sera utilisé à la place:

class Rabbit extends Animal { stop() { // ...now this will be used for rabbit.stop() // instead of stop() from class Animal }}

Habituellement, nous ne voulons pas remplacer totalement un parent méthode, mais plutôt de construire au-dessus d’elle pour la modifier ou étendre ses fonctionnalités. Nous faisons quelque chose dans notre méthode, mais appelons la méthode parent avant/après ou dans le processus.

Les Classes fournissent le mot-clé"super" pour cela.

  • super.method(...) pour appeler une méthode parent.,
  • super(...) pour appeler un constructeur parent (à l’intérieur de notre constructeur uniquement).

Par exemple, que notre lapin de masquage automatique lors de l’arrêt:

Maintenant Rabbit le stop méthode qui appelle le parent super.stop() dans le processus.

remplacer le constructeur

avec les constructeurs, cela devient un peu délicat.

Jusqu’à maintenant, Rabbit n’a pas son propre constructor.,

Selon la spécification, si une classe étend une autre classe et n’a pas de constructor, puis le suivant « vide” constructor est généré:

class Rabbit extends Animal { // generated for extending classes without own constructors constructor(...args) { super(...args); }}

Comme on peut le voir, essentiellement, il appelle le parent constructor le passant tous les arguments. Cela se produit si nous n’écrivons pas notre propre constructeur.

ajoutons maintenant un constructeur personnalisé àRabbit. Il permettra de spécifier la balise earLength outre name:

Oups!, Nous avons eu une erreur. Maintenant, nous ne pouvons pas créer de lapins. Quel est le problème?

la réponse courte est:

  • Les constructeurs dans les classes héritantes doivent appelersuper(...), et (!) le faire avant d’utiliser this.

…Mais pourquoi? Ce qui se passe ici? En effet, l’exigence semble étrange.

bien sûr, il y a une explication. Entrons dans les détails, donc vous comprendrez vraiment ce qui se passe.

en JavaScript, il existe une distinction entre une fonction constructeur d’une classe héritante (appelée « constructeur dérivé”) et d’autres fonctions., Un constructeur dérivé a une propriété interne spéciale ]:"derived". C’est une étiquette interne spéciale.

Cette étiquette affecte son comportement avec des new.

  • lorsqu’une fonction régulière est exécutée avec new, elle crée un objet vide et l’assigne à this.
  • Mais quand un constructeur dérivé s’exécute, il ne le fait pas. Il s’attend à ce que le constructeur parent effectue ce travail.,

Un constructeur dérivé doit donc appelersuper afin d’exécuter son constructeur parent (de base), sinon l’objet pourthis ne sera pas créé. Et nous allons avoir une erreur.

Pour le Rabbit constructeur de travail, il doit appeler super() avant d’utiliser this, comme ici:

classe prioritaire champs: une délicate note

Avancé remarque

Cette remarque suppose que vous avez une certaine expérience avec les classes, peut-être dans d’autres langages de programmation.,

Il fournit un meilleur aperçu du langage et explique également le comportement qui pourrait être une source de bogues (mais pas très souvent).

Si vous avez du mal à comprendre, continuez, continuez à lire, puis revenez-y quelque temps plus tard.

On peut remplacer non seulement les méthodes, mais aussi les champs de la classe.

cependant, il y a un comportement délicat lorsque nous accédons à un champ surchargé dans le constructeur parent, assez différent de la plupart des autres langages de programmation.,

prenons l’exemple suivant:

Ici, la classe Rabbit extends Animal et remplace name champ avec sa propre valeur.

Il n’y a pas de propre constructeur dans Rabbit, donc Animal constructeur est appelé.

Ce qui est intéressant, c’est que dans les deux cas: new Animal() et new Rabbit(), le alert à la ligne (*) montre animal.,

En d’autres termes, constructeur parent utilise toujours sa propre valeur de champ, pas substituées l’une.

Qu’est-ce qui est étrange à ce sujet?

Si ce n’est pas encore clair, veuillez comparer avec les méthodes.

Voici le même code, mais au lieu de this.name domaine que nous appelons this.showName() méthode:

Veuillez noter: maintenant, le résultat est différent.

et c’est ce que nous attendons naturellement. Lorsque le constructeur parent est appelé dans la classe dérivée, il utilise la méthode de remplacement.

But mais pour les champs de classe, ce n’est pas le cas. Comme dit, le constructeur parent utilise toujours le champ parent.,

Pourquoi y a-t-il la différence?

Eh bien, la raison est dans l’ordre d’initialisation du champ. Le champ de classe est initialisé:

  • avant le constructeur pour la classe de base (qui n’étend rien),
  • immédiatement après super() pour la classe dérivée.

Dans notre cas, Rabbit est la classe dérivée. Il n’y a pas de constructor() dedans. Comme dit précédemment, c’est la même chose que s’il y avait un constructeur vide avec seulement super(...args).,

donc,new Rabbit() appellesuper(), exécutant ainsi le constructeur parent, et (selon la règle pour les classes dérivées) seulement après que ses champs de classe sont initialisés. Au moment de l’exécution du constructeur parent, il n’y a pas encore de champs de classe Rabbit, c’est pourquoi les champs Animal sont utilisés.

Cette différence subtile entre les champs et les méthodes est spécifique à JavaScript

heureusement, ce comportement ne se révèle que si un champ surchargé est utilisé dans le constructeur parent., Ensuite, il peut être difficile de comprendre ce qui se passe, donc nous l’expliquons ici.

si cela devient un problème, on peut le résoudre en utilisant des méthodes ou des getters / setters au lieu de champs.

Super: internals,]

informations avancées

Si vous lisez le tutoriel pour la première fois – cette section peut être ignorée.

Il s’agit des mécanismes internes derrière l’héritage etsuper.

nous allons obtenir un peu plus sous le capot de super. Nous verrons des choses intéressantes en cours de route.,

tout d’abord, d’après tout ce que nous avons appris jusqu’à présent, il est impossible que super fonctionne du tout!

Oui, en effet, demandons-nous, comment cela devrait fonctionner techniquement? Lorsqu’une méthode object s’exécute, elle obtient l’objet actuel sous la forme this. Si nous appelons super.method() alors, le moteur doit obtenir le method à partir du prototype de l’objet actuel. Mais comment?

la tâche peut sembler simple, mais ce n’est pas le cas., Le moteur sait que l’objet en cours this, de sorte qu’il pourrait obtenir le parent method this.__proto__.method. Malheureusement, une telle solution « naïve » ne fonctionnera pas.

nous allons démontrer le problème. Sans classes, en utilisant des objets simples pour des raisons de simplicité.

Vous pouvez ignorer cette partie et aller ci-dessous à la sous-section] si vous ne voulez pas connaître les détails. Que ne fera pas de mal. Ou lisez la suite si vous souhaitez comprendre les choses en profondeur.

Dans l’exemple ci-dessous, rabbit.__proto__ = animal., Maintenant, nous allons essayer: dans rabbit.eat() nous appellerons animal.eat(), à l’aide de this.__proto__:

À la ligne (*) nous prenons eat le prototype (animal) et de l’appeler dans le contexte de l’objet courant. Veuillez noter que .call(this) est important ici, car un simple this.__proto__.eat() exécutera le parent eat dans le contexte du prototype, pas dans l’objet courant.,

et dans le code ci-dessus, cela fonctionne réellement comme prévu: nous avons le bon alert.

ajoutons maintenant un objet de plus à la chaîne. Nous verrons comment les choses se cassent:

le code ne fonctionne plus! On peut voir l’erreur en essayant d’appeler longEar.eat().

ce n’est peut-être pas si évident, mais si nous suivons l’appellongEar.eat(), alors nous pouvons voir pourquoi. Dans les deux lignes (*) et (**) la valeur this est l’objet courant (longEar)., C’est essentiel: toutes les méthodes d’objet obtiennent l’objet actuel comme this, pas un prototype ou quelque chose.

Voici l’image de ce qui se passe:

Le problème ne peut être résolu à l’aide de this seul.

]

pour fournir la solution, JavaScript ajoute une autre propriété interne spéciale pour les fonctions:].,

Lorsqu’une fonction est spécifiée en tant que méthode de classe ou d’objet, sa propriété] devient cet objet.

puissuper l’utilise pour résoudre le prototype parent et ses méthodes.

voyons comment cela fonctionne, d’abord avec des objets simples:

les méthodes ne sont pas « libres”

Comme nous l’avons déjà connu, les fonctions sont généralement « libres”, pas liées à des objets en JavaScript. Ils peuvent donc être copiés entre des objets et appelés avec un autre this.,

l’existence même de ] viole ce principe, car les méthodes se souviennent de leurs objets. ] ne peut pas être modifié, donc cette liaison est éternelle.

Le seul endroit dans la langue où ] est utilisé – est de super. Donc, si une méthode n’utilise pas super, alors nous pouvons toujours la considérer libre et la copier entre les objets. Mais avec super les choses peuvent mal tourner.,

Voici la démo d’un mauvais super résultat après la copie:

Un appel à tree.sayHi() affiche « je suis un animal”. Certainement mauvais.

La raison est simple:

Voici le schéma de ce qui se passe:

de Méthodes, propriétés de la fonction

La différence peut être non-essentiel pour nous, mais il est important pour le JavaScript.

Dans l’exemple ci-dessous, une non-méthode syntaxe est utilisée pour la comparaison., ] propriété n’est pas définie et l’héritage ne fonctionne pas:

Résumé

  1. Pour étendre une classe: class Child extends Parent:
    • Qui signifie Child.prototype.__proto__ sera Parent.prototype, afin que les méthodes sont héritées.
  2. Lors de la substitution d’un constructeur:
    • Nous devez appeler le constructeur parent super() dans un Child constructeur avant d’utiliser this.,
  3. Lors de la substitution d’une autre méthode:
    • On peut utiliser super.method() dans un Child méthode à appeler Parent méthode.
  4. internes:
    • Les méthodes mémorisent leur classe/objet dans la propriété interne]. C’est ainsi que super résout les méthodes parentes.
    • il n’est Donc pas sûr de copier une méthode avec des super d’un objet à un autre.,

Aussi:

  • Flèche fonctions n’ont pas leur propre this ou super, de façon transparente, de sorte qu’ils s’insèrent dans le contexte environnant.