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 prototypeObjekts. Das Überschreiben eines prototypeObjekts 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 newmit '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 - adamInstanz, und schauen Sie die prototypische Kette der jeweils .prototype, das ist Person.prototype- und Person.prototype hat eine .speciesEigenschaft, so dass die Lookup auf Erfolg haben wird Person.prototype. Es wird dann protokolliert'human' .
Hier zeigt der Person.prototype.constructorWille richtig auf Person.
Nun also der interessante Teil, die sogenannte "Unterklasse". Wenn wir eine StudentKlasse erstellen möchten, dh eine Unterklasse der PersonKlasse mit einigen zusätzlichen Änderungen, müssen wir sicherstellen, dass die Student.prototype.constructorPunkte 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 Persontrue zurückgegeben wird und Instanzen der StudentDelegierung korrekt an Student.prototypeund dann gesendet werden Person.prototype.
ABER da wir es mit dem newSchlüsselwort aufrufen , erinnern Sie sich, was dieser Aufruf hinzufügt? Es würde heißen Object.create(Student.prototype), wie wir diese Delegationsbeziehung zwischen Studentund aufbauen Student.prototype. Beachten Sie, dass im Moment Student.prototypeleer ist. So aufzublicken .specieseine Instanz Studentfehlschlagen würde , wie es Delegierten nur Student.prototype , und die .speciesEigenschaft existiert nicht auf Student.prototype.
Wenn wir assign tun Student.prototypezu Object.create(Person.prototype), Student.prototypeselbst dann Delegierten Person.prototypeund aufzublicken eve.specieszurückkehren wird , humanwie 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.prototypemit einem von Person.prototype. Wenn wir also anrufen Student.prototype.constructor, würde es auf Personstatt 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 constructorEigenschaft 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 constructorjetzt 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, superwenn 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;
}
}