TLDR; Pas super nécessaire, mais aidera probablement à long terme, et il est plus précis de le faire.
REMARQUE: Beaucoup de choses ont été modifiées car ma réponse précédente a été écrite de manière confuse et contient des erreurs que j'ai manquées dans ma précipitation à répondre. Merci à ceux qui ont signalé des erreurs flagrantes.
Fondamentalement, il s'agit de câbler correctement le sous-classement en Javascript. Lorsque nous sous-classons, nous devons faire des choses amusantes pour nous assurer que la délégation prototypique fonctionne correctement, notamment en écrasant un prototypeobjet. Le remplacement d'un prototypeobjet inclut le constructor, nous devons donc corriger la référence.
Voyons rapidement comment fonctionnent les «classes» dans ES5.
Disons que vous avez une fonction constructeur et son prototype:
//Constructor Function
var Person = function(name, age) {
this.name = name;
this.age = age;
}
//Prototype Object - shared between all instances of Person
Person.prototype = {
species: 'human',
}
Lorsque vous appelez le constructeur pour instancier, dites Adam:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
Le newmot-clé invoqué avec 'Person' exécutera le constructeur Person avec quelques lignes de code supplémentaires:
function Person (name, age) {
// This additional line is automatically added by the keyword 'new'
// it sets up the relationship between the instance and the prototype object
// So that the instance will delegate to the Prototype object
this = Object.create(Person.prototype);
this.name = name;
this.age = age;
return this;
}
/* So 'adam' will be an object that looks like this:
* {
* name: 'Adam',
* age: 19
* }
*/
Si nous console.log(adam.species), la recherche échouera à l' adaminstance et recherchera la chaîne prototypique vers la sienne .prototype, qui est Person.prototype- et Person.prototype possède une .speciespropriété, la recherche réussira donc Person.prototype. Il se connectera ensuite 'human'.
Ici, le Person.prototype.constructorpointera correctement Person.
Alors maintenant, la partie intéressante, le soi-disant «sous-classement». Si nous voulons créer une Studentclasse, c'est-à-dire une sous-classe de la Personclasse avec quelques modifications supplémentaires, nous devons nous assurer que les Student.prototype.constructorpoints pointent vers Student pour plus de précision.
Il ne le fait pas tout seul. Lorsque vous sous-classe, le code ressemble à ceci:
var Student = function(name, age, school) {
// Calls the 'super' class, as every student is an instance of a Person
Person.call(this, name, age);
// This is what makes the Student instances different
this.school = school
}
var eve = new Student('Eve', 20, 'UCSF');
console.log(Student.prototype); // this will be an empty object: {}
Appeler new Student()ici retournerait un objet avec toutes les propriétés que nous voulons. Ici, si nous vérifions eve instanceof Person, cela reviendrait false. Si nous essayons d'accéder eve.species, il reviendrait undefined.
En d'autres termes, nous devons câbler la délégation afin que eve instanceof Personrenvoie true et que les instances de Studentdélégué soient correctement envoyées à Student.prototype, puis Person.prototype.
MAIS puisque nous l'appelons avec le newmot - clé, rappelez-vous ce que cette invocation ajoute? Cela s'appellerait Object.create(Student.prototype), c'est ainsi que nous établissons cette relation de délégation entre Studentet Student.prototype. Notez qu'en ce moment, Student.prototypeest vide. Ainsi, la recherche d' .speciesune instance de Studentéchouerait car elle délègue uniquement Student.prototype et la .speciespropriété n'existe pas Student.prototype.
Lorsque nous nous attribuons Student.prototypeà Object.create(Person.prototype), Student.prototypelui - même , les délégués sont Person.prototyperenvoyés et la recherche eve.speciesrevient humancomme prévu. Vraisemblablement, nous voudrions qu'il hérite de Student.prototype ET Person.prototype. Nous devons donc régler tout cela.
/* This sets up the prototypal delegation correctly
*so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
*This also allows us to add more things to Student.prototype
*that Person.prototype may not have
*So now a failed lookup on an instance of Student
*will first look at Student.prototype,
*and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);
Maintenant, la délégation fonctionne, mais nous remplaçons Student.prototypepar un de Person.prototype. Donc, si nous appelons Student.prototype.constructor, cela indiquerait au Personlieu de Student. C'est pourquoi nous devons y remédier.
// Now we fix what the .constructor property is pointing to
Student.prototype.constructor = Student
// If we check instanceof here
console.log(eve instanceof Person) // true
Dans ES5, notre constructorpropriété est une référence qui fait référence à une fonction que nous avons écrite avec l'intention d'être un «constructeur». Mis à part ce que le newmot - clé nous donne, le constructeur est par ailleurs une fonction «simple».
Dans ES6, le constructorest désormais intégré dans la façon dont nous écrivons les classes - comme dans, il est fourni comme méthode lorsque nous déclarons une classe. Il s'agit simplement de sucre syntaxique, mais il nous offre certaines commodités comme l'accès à un superlorsque nous étendons une classe existante. Nous écririons donc le code ci-dessus comme ceci:
class Person {
// constructor function here
constructor(name, age) {
this.name = name;
this.age = age;
}
// static getter instead of a static property
static get species() {
return 'human';
}
}
class Student extends Person {
constructor(name, age, school) {
// calling the superclass constructor
super(name, age);
this.school = school;
}
}