TLDR; Не очень необходимо, но, вероятно, поможет в долгосрочной перспективе, и это более точно.
ПРИМЕЧАНИЕ. Многое редактировалось, поскольку мой предыдущий ответ был смущенно написан и имел некоторые ошибки, которые я пропустил в моей спешке, чтобы ответить. Спасибо тем, кто указал на некоторые вопиющие ошибки.
В принципе, для правильного подключения к подклассу в Javascript. Когда мы подклассом, мы должны сделать некоторые напуганные вещи, чтобы убедиться, что прототипная делеция работает правильно, включая перезапись объекта prototype
. Перезапись объекта prototype
включает в себя constructor
, поэтому нам нужно исправить ссылку.
Давайте быстро рассмотрим, как работают «классы» в ES5.
Допустим, вы имеют конструкторскую функцию и ее прототип:
//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',
}
Когда вы вызываете конструктор для создания экземпляра, скажем Adam
:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
Ключевое слово new
вызывается с помощью «Человек» 'в основном будет запускать конструктор Person с несколькими дополнительными строками кода:
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
* }
*/
Если мы console.log(adam.species)
, поиск не будет выполняться на экземпляре adam
и будет искать прототипную цепочку для его .prototype
, который есть Person.prototype
- и Person.prototype
, имеет свойство a .species
, поэтому поиск будет успешным на Person.prototype
. Затем он будет записывать 'human'
.
Здесь Person.prototype.constructor
будет правильно указывать на Person
.
Итак, теперь интересная часть - так называемое «подклассификация». Если мы хотим создать класс Student
, являющийся подклассом класса Person
с некоторыми дополнительными изменениями, нам нужно убедиться, что Student.prototype.constructor
указывает на точность для ученика.
Это не делается само по себе. При подклассе код выглядит следующим образом:
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: {}
Вызов new Student()
здесь возвращает объект со всеми требуемыми свойствами. Здесь, если мы проверим eve instanceof Person
, он вернется false
. Если мы попытаемся получить доступ к eve.species
, он вернет undefined
.
Другими словами, нам нужно связать делегирование, чтобы eve instanceof Person
возвращало true и чтобы экземпляры делегата Student
правильно Student.prototype
, а затем Person.prototype
.
НО, так как мы вызываем его с ключевым словом new
, помните, что добавляет этот призыв? Он назовет Object.create(Student.prototype)
, как мы установили это делегиальное отношение между Student
и Student.prototype
. Обратите внимание, что прямо сейчас Student.prototype
пуст. Таким образом, при поиске .species
экземпляр Student
потерпит неудачу, поскольку он делегирует только Student.prototype
, а свойство .species
не существует на Student.prototype
.
Когда мы присваиваем Student.prototype
Object.create(Person.prototype)
, сам Student.prototype
делегирует Person.prototype
, и поиск eve.species
вернет human
, как мы ожидаем. Предположительно, мы хотели бы, чтобы он наследовал от Student.prototype AND Person.prototype. Поэтому нам нужно все это исправить.
/* 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);
Теперь делегация работает, но мы переписываем Student.prototype
с помощью функции Person.prototype
. Поэтому, если мы назовем Student.prototype.constructor
, он будет указывать на Person
вместо Student
. Вот почему мы должны это исправить.
// 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
В ES5 наше свойство constructor
является ссылкой, которая ссылается на функцию, которую мы написали с намерением стать «конструктором». Помимо того, что дает нам ключевое слово new
, конструктор в противном случае является «простой» функцией.
В ES6 constructor
теперь встроен в способ, которым мы пишем классы - как в, он предоставляется как метод, когда мы объявляем класс. Это просто синтаксический сахар, но он предоставляет нам некоторые удобства, такие как доступ к super
, когда мы расширяем существующий класс. Поэтому мы должны написать вышеприведенный код следующим образом:
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;
}
}