TLDR; Nie jest to konieczne, ale prawdopodobnie pomoże na dłuższą metę i jest to bardziej dokładne.
UWAGA: Wiele zredagowałem, ponieważ moja poprzednia odpowiedź była myląco napisana i zawierała błędy, których nie spóźniłem się z odpowiedzią. Dzięki tym, którzy wskazali na pewne rażące błędy.
Zasadniczo ma to na celu prawidłowe podklasowanie w JavaScript. Kiedy dokonujemy podklasy, musimy zrobić kilka dziwnych rzeczy, aby upewnić się, że delegacja prototypowa działa poprawnie, w tym nadpisanie prototype
obiektu. Nadpisanie prototype
obiektu obejmujeconstructor
, dlatego musimy naprawić odwołanie.
Zobaczmy, jak działają „klasy” w ES5.
Powiedzmy, że masz funkcję konstruktora i jej 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',
}
Po wywołaniu konstruktora w celu utworzenia wystąpienia, powiedz Adam
:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
new
Kluczowe wywołany z „osoba” w zasadzie będzie działać konstruktora osoba z kilku dodatkowych linii kodu:
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
* }
*/
Gdybyśmy console.log(adam.species)
, odnośnika zawiedzie na adam
przykład, i patrzeć prototypal łańcuch do swojego .prototype
, co jest Person.prototype
- i Person.prototype
ma na .species
własność, więc wyszukiwanie na uda Person.prototype
. Następnie się zaloguje'human'
.
Tutaj Person.prototype.constructor
poprawnie wskaże Person
.
Więc teraz interesująca część, tak zwane „podklasowanie”. Jeśli chcemy stworzyć Student
klasę, która jest podklasą Person
klasy z pewnymi dodatkowymi zmianami, musimy upewnić się, że Student.prototype.constructor
punkty wskazują Uczniowi na dokładność.
Sam tego nie robi. Podklasę kod wygląda następująco:
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: {}
Wywołanie new Student()
tutaj zwróci obiekt ze wszystkimi pożądanymi właściwościami. Tutaj, jeśli sprawdzimy eve instanceof Person
, wróci false
. Jeśli spróbujemy uzyskać dostęp eve.species
, nastąpi powrót undefined
.
Innymi słowy, musimy uporządkować delegację, aby eve instanceof Person
zwracała wartość true, a instancje Student
delegowania były poprawnie przesyłane do Student.prototype
, a następnie Person.prototype
.
ALE, ponieważ nazywamy to new
słowem kluczowym, pamiętasz, co dodaje to wywołanie? To by zadzwoniło Object.create(Student.prototype)
, w ten sposób ustanowiliśmy relacje delegacyjne pomiędzy Student
i Student.prototype
. Zauważ, że teraz Student.prototype
jest pusty. Dlatego wyszukiwanie .species
instancji Student
nie powiedzie się, ponieważ deleguje ją tylko Student.prototype
, a .species
właściwość nie istnieje Student.prototype
.
Kiedy przydzielimy Student.prototype
do Object.create(Person.prototype)
, Student.prototype
sama deleguje się do Person.prototype
, a wyszukiwanie eve.species
wróci, human
jak się spodziewamy. Przypuszczalnie chcielibyśmy, aby odziedziczył po Student.prototype AND Person.prototype. Musimy to wszystko naprawić.
/* 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);
Teraz delegacja działa, ale zastępujemy Student.prototype
ją Person.prototype
. Więc jeśli zadzwonimy Student.prototype.constructor
, wskazywałoby to na Person
zamiast Student
. To dlatego musimy go naprawić.
// 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
W ES5 nasza constructor
właściwość jest referencją odnoszącą się do funkcji, którą napisaliśmy z zamiarem bycia „konstruktorem”. Oprócz tego, co new
daje nam słowo kluczowe, konstruktor jest poza tym „prostą” funkcją.
W ES6 constructor
jest teraz wbudowany w sposób, w jaki piszemy klasy - podobnie jak w, jest on dostarczany jako metoda, gdy deklarujemy klasę. Jest to po prostu cukier składniowy, ale zapewnia nam pewne udogodnienia, takie jak dostęp do super
kiedy rozszerzamy istniejącą klasę. Więc napisalibyśmy powyższy kod w ten sposób:
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;
}
}