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 prototypeobiektu. Nadpisanie prototypeobiektu 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);
newKluczowe 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 adamprzykład, i patrzeć prototypal łańcuch do swojego .prototype, co jest Person.prototype- i Person.prototype ma na .specieswłasność, więc wyszukiwanie na uda Person.prototype. Następnie się zaloguje'human' .
Tutaj Person.prototype.constructorpoprawnie wskaże Person.
Więc teraz interesująca część, tak zwane „podklasowanie”. Jeśli chcemy stworzyć Studentklasę, która jest podklasą Personklasy z pewnymi dodatkowymi zmianami, musimy upewnić się, że Student.prototype.constructorpunkty 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 Personzwracała wartość true, a instancje Studentdelegowania były poprawnie przesyłane do Student.prototype, a następnie Person.prototype.
ALE, ponieważ nazywamy to newsł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 Studenti Student.prototype. Zauważ, że teraz Student.prototypejest pusty. Dlatego wyszukiwanie .speciesinstancji Studentnie powiedzie się, ponieważ deleguje ją tylko Student.prototype , a .specieswłaściwość nie istnieje Student.prototype.
Kiedy przydzielimy Student.prototypedo Object.create(Person.prototype), Student.prototypesama deleguje się do Person.prototype, a wyszukiwanie eve.specieswróci, humanjak 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.prototypeją Person.prototype. Więc jeśli zadzwonimy Student.prototype.constructor, wskazywałoby to na Personzamiast 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 constructorwłaściwość jest referencją odnoszącą się do funkcji, którą napisaliśmy z zamiarem bycia „konstruktorem”. Oprócz tego, co newdaje nam słowo kluczowe, konstruktor jest poza tym „prostą” funkcją.
W ES6 constructorjest 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 superkiedy 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;
}
}