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", в основном будет работатьконструктор 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
, котораяis 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
завершится неудачей, поскольку он делегирует only 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;
}
}