предисловие
Эта статья написана после прочтения учебника по es6 учителя Руана, см.superКогда дело доходит до ключевых слов, я считаю необходимым обобщить и разобраться, исходный текст все еще является ссылкойНачало работы с ECMAScript 6.
текст
superЭто ключевое слово может использоваться и как функция, и как объект.
1. Использовать как функцию
superКогда он вызывается как функция, он представляет конструктор родительского класса.ES6Требует, чтобы конструктор подкласса был выполнен один разsuperфункция.
то есть как函数При использовании кода ниже固定使用套路:
class A {
constrctor(){
}
}
class B extends A {
constructor() {
super();
}
}
Кого представляет super() в приведенном выше коде? ?
ПодклассBв конструктореsuper(),представлятьBвызвать родительский классAКонструктор выполняется.
Примечание⚠️: хотяsuper()представленный родительским классомAконструктор, но возвращает подклассBэкземпляр, то естьsuper()Внутреннее this относится к B, поэтомуsuper()здесь эквивалентноA.prototype.constructor.call(this).
Большой каштан в доказательство моего тезиса:
class A {
constrctor(){
console.log(new.target.name)
}
}
class B extends A{
constructor(){
super()
}
}
new A() // A
new B() // B
В этом парном кодеnew.targetУказывает на текущую выполняемую функцию.
Мягко говоря:
newэто команда для экземпляра объекта, сгенерированного из конструктора. ES6 этоnewкоманда вводитnew.targetАтрибут, который обычно используется в конструкторах и возвращает конструктор, над которым действует новая команда.
Видно, что вsuper()При выполнении он указывает на подклассBконструктор, а не родительский классAконструктор. которыйsuper()Внутреннее это относится кB.
Еще один момент, который следует отметить⚠️:
Как функцию Super() можно использовать только в конструкторе подклава, а использовать его в других местах.
// 错误写法
class A {}
class B extends A {
m() {
super(); // 报错
}
}
В заключение:
При использовании super в качестве функции необходимо обратить внимание на следующие три момента:
- Конструктор подкласса должен быть выполнен один раз
superфункция.
// 再次重申,这是固定写法
class A {
constructor() {}
}
class B extends A {
constructor() {
super();// 这里表示 A.constructor()
}
}
- в конструкторе подкласса
super()Это означает, что подкласс вызывает конструктор родительского класса для выполнения, в это времяsuper()это в父类.constructorсерединаthis, который относится к подклассу.
3.super() можно использовать только в конструкторе подкласса, а в других местах будет сообщено об ошибке.
2. Когда super — это объект
superВ качестве объекта в обычном методе он указывает на объект-прототип родительского класса, а в статическом методе — на родительский класс.
2.1 super используется как объект в обычных методах
Над кодом:
class A {
p(){
return 2
}
}
class B extends A {
constrctor(){
super();
console.log(super.p());//2
}
}
let b = new B();
Мы обнаружили, что в подклассеBсерединаsuper.p()Результат выполнения2. Мы предполагаем здесьsupsuper.p === A.prototype.p, убедитесь, что результатtrue:
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p===A.prototype.p); // true
}
}
let b = new B();
То есть в это времяsuperВ обычном методе, указывая наA.prototypeто есть в подклассеsuperУказатель на объект-прототип родительского класса.
⚠️Примечание 1.: из-заsuperОн указывает на объект-прототип родительского класса, поэтому методы или свойства, определенные в экземпляре родительского класса, не могут быть переданы.superназывается.
class A {
constructor() {
this.s = 3;
}
}
A.prototype.x = 2;
class B extends A {
constructor() {
super();
console.log(super.x) // 2 这里可以获取到父类原型上的x属性
}
get m(){
return super.s
}
}
let b = new B();
console.log(b.m)// undefined 不能获取到定义在父类实例上的s属性
Через приведенный выше код мы находим:
ПодклассBв состоянии пройтиsuperПолучить свойства, определенные в прототипе родительского класса, но определенные в родительском классеAНе удалось получить свойства экземпляра .
Заметка 2⚠️:это указывает на
ES6 предусматривает, что в подклассе передается обычный методsuperПри вызове метода родительского класса метод внутри методаthisУказывает на текущий экземпляр подкласса.
class A {
constructor() {
this.x = 1;
}
print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
m() {
super.print();// 这里等同于 A.proptotype.print()
}
}
let b = new B();
b.m() // 2
В приведенном выше кодеsuper.print()Хотя звонитA.prototype.print(),ноA.prototype.print()Внутреннее this указывает на экземпляр подкласса B, что приводит к 2 вместо 1. То есть то, что на самом деле выполняется,super.print.call(this).
Заметка 3⚠️:пройти черезsuperвыполнить задание
из-заthisуказывает на экземпляр подкласса, поэтому, если вы передадитеsuperПрисвойте значение свойству, затемsuperто естьthis, назначенное свойство становится свойством экземпляра подкласса.
class A {
constructor() {
this.x = 1;
}
}
class B extends A {
constructor() {
super();
this.x = 2;
super.x = 3;// 此时的 super 就是 b
console.log(super.x); // undefined 等用于是 A.prototype.x
console.log(this.x); // 3
}
}
let b = new B();
Через эти два куска кода мы нашли проблему, когда я прохожуsuperКогда принимается значение, берется свойство прототипа родительского класса, но когда я передаюsuperпри назначенииsuperУказывает на экземпляр подкласса.
В заключение:
Из трех каштанов выше,superПри применении в обычном методе в качестве объекта:
- в подклассе
superОн указывает на объект-прототип родительского класса, поэтому методы или свойства, определенные в экземпляре родительского класса, не могут быть переданы.superназывается. - Передайте нормальный метод подкласса
superПри вызове метода родительского класса this внутри метода указывает на текущий экземпляр подкласса. - Назначьте свойство свойству через super, затем super is this, и назначенное свойство станет свойством экземпляра подкласса.
2.2 super применяется как объект в статическом методе
еслиsuperКак объект, используемый в статическом методе, затемsuperбудет указывать на родительский класс, а не на родительский объект-прототип.
class Parent {
static myMethod(msg) {
console.log('static', msg);
}
myMethod(msg) {
console.log('instance', msg);
}
}
class Child extends Parent {
static myMethod(msg) {
// 此时的 super 指的是父类,Parent
super.myMethod(msg);
}
myMethod(msg) {
// 普通函数 此时 super 是指 Parent.prototype
super.myMethod(msg);
}
}
Child.myMethod(1); // static 1
var child = new Child();
child.myMethod(2); // instance 2
В приведенном выше коде super указывает на родительский класс в статическом методе и указывает на объект-прототип родительского класса в обычном методе.
Примечание 1 ⚠️
в статическом методе подкласса черезsuperПри вызове метода родительского класса метод внутри методаthisУказывает на текущий подкласс, а не на экземпляр подкласса.
class A {
constructor() {
this.x = 1;
}
static print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
static m() {
super.print();// A.print 中的this指向当前的子类
}
}
B.x = 3;
B.m() // 3
В приведенном выше коде статический методB.mв,super.printСтатический метод, указывающий на родительский класс. в этом методеthisуказывает наB, вместоBпример.
В заключение:
в статическом методе подкласса черезsuperПри вызове метода родительского класса метод внутри методаthisУказывает на текущий подкласс, а не на экземпляр подкласса.
во всяком случае
-
superкак функция,super()Представляет конструктор родительского класса внутриthisявляется экземпляром класса. -
superкак объект, в обычном методеsuper.Синтаксис указывает на объект-прототип родительского класса, который используется в статических методах.super.Синтаксис заключается в том, чтобы перейти к статическому методу родительского класса, чтобы найти его. Что касаетсяthisУкажите на вопрос, помните одну вещь:Если перед методом добавитьstaticключевое слово, оно означает, что метод не будет унаследован экземпляром, а будет вызываться напрямую через класс, поэтому в статическом методеthisбудет ссылаться только на классы, а не на экземпляры.