TLDR; Nicht besonders notwendig, wird aber wahrscheinlich auf lange Sicht helfen, und es ist genauer, dies zu tun.
HINWEIS: Viel bearbeitet, da meine vorherige Antwort verwirrend geschrieben war und einige Fehler aufwies, die ich in meiner Eile zur Beantwortung verpasst hatte. Vielen Dank an diejenigen, die auf einige ungeheure Fehler hingewiesen haben.
Grundsätzlich geht es darum, Unterklassen in Javascript korrekt zu verdrahten. Wenn wir eine Unterklasse erstellen, müssen wir einige funky Dinge tun, um sicherzustellen, dass die prototypische Delegierung ordnungsgemäß funktioniert, einschließlich des Überschreibens eines prototype
Objekts. Das Überschreiben eines prototype
Objekts umfasst dieconstructor
, daher müssen wir die Referenz korrigieren.
Lassen Sie uns kurz durchgehen, wie 'Klassen' in ES5 funktionieren.
Angenommen, Sie haben eine Konstruktorfunktion und ihren Prototyp:
//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',
}
Wenn Sie den Konstruktor zum Instanziieren aufrufen, sagen Sie Adam
:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
Das new
mit 'Person' aufgerufene Schlüsselwort führt den Personenkonstruktor grundsätzlich mit einigen zusätzlichen Codezeilen aus:
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
* }
*/
Wenn wir console.log(adam.species)
, wird die Suche in der Fail - adam
Instanz, und schauen Sie die prototypische Kette der jeweils .prototype
, das ist Person.prototype
- und Person.prototype
hat eine .species
Eigenschaft, so dass die Lookup auf Erfolg haben wird Person.prototype
. Es wird dann protokolliert'human'
.
Hier zeigt der Person.prototype.constructor
Wille richtig auf Person
.
Nun also der interessante Teil, die sogenannte "Unterklasse". Wenn wir eine Student
Klasse erstellen möchten, dh eine Unterklasse der Person
Klasse mit einigen zusätzlichen Änderungen, müssen wir sicherstellen, dass die Student.prototype.constructor
Punkte für die Genauigkeit auf Student zeigen.
Das macht es nicht alleine. Wenn Sie eine Unterklasse erstellen, sieht der Code folgendermaßen aus:
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: {}
Wenn Sie new Student()
hier aufrufen, wird ein Objekt mit allen gewünschten Eigenschaften zurückgegeben. Hier, wenn wir überprüfen eve instanceof Person
, würde es zurückkehren false
. Wenn wir versuchen, darauf zuzugreifen eve.species
, würde es zurückkehrenundefined
.
Mit anderen Worten, wir müssen die Delegierung so verkabeln, dass eve instanceof Person
true zurückgegeben wird und Instanzen der Student
Delegierung korrekt an Student.prototype
und dann gesendet werden Person.prototype
.
ABER da wir es mit dem new
Schlüsselwort aufrufen , erinnern Sie sich, was dieser Aufruf hinzufügt? Es würde heißen Object.create(Student.prototype)
, wie wir diese Delegationsbeziehung zwischen Student
und aufbauen Student.prototype
. Beachten Sie, dass im Moment Student.prototype
leer ist. So aufzublicken .species
eine Instanz Student
fehlschlagen würde , wie es Delegierten nur Student.prototype
, und die .species
Eigenschaft existiert nicht auf Student.prototype
.
Wenn wir assign tun Student.prototype
zu Object.create(Person.prototype)
, Student.prototype
selbst dann Delegierten Person.prototype
und aufzublicken eve.species
zurückkehren wird , human
wie wir es erwarten. Vermutlich möchten wir, dass es von Student.prototype AND Person.prototype erbt. Also müssen wir das alles beheben.
/* 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);
Jetzt funktioniert die Delegation, aber wir überschreiben Student.prototype
mit einem von Person.prototype
. Wenn wir also anrufen Student.prototype.constructor
, würde es auf Person
statt zeigen Student
. Dies ist , warum wir es beheben müssen.
// 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
In ES5 ist unsere constructor
Eigenschaft eine Referenz, die sich auf eine Funktion bezieht, die wir mit der Absicht geschrieben haben, ein 'Konstruktor' zu sein. Abgesehen von dem, was dienew
Schlüsselwort uns gibt, ist der Konstruktor ansonsten eine 'einfache' Funktion.
In ES6 ist das constructor
jetzt in die Art und Weise integriert, wie wir Klassen schreiben - wie in wird es als Methode bereitgestellt, wenn wir eine Klasse deklarieren. Dies ist einfach syntaktischer Zucker, aber es bietet uns einige Annehmlichkeiten wie den Zugang zu einem, super
wenn wir eine bestehende Klasse erweitern. Also würden wir den obigen Code so schreiben:
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;
}
}