Вы действительно понимаете ключевое слово [супер]?

внешний интерфейс ECMAScript 6

image

предисловие

Эта статья написана после прочтения учебника по 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 в качестве функции необходимо обратить внимание на следующие три момента:

  1. Конструктор подкласса должен быть выполнен один разsuperфункция.
// 再次重申,这是固定写法
class A {
 constructor() {}
}

class B extends A {
  constructor() {
    super();// 这里表示 A.constructor()
  }
}
  1. в конструкторе подкласса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При применении в обычном методе в качестве объекта:

  1. в подклассеsuperОн указывает на объект-прототип родительского класса, поэтому методы или свойства, определенные в экземпляре родительского класса, не могут быть переданы.superназывается.
  2. Передайте нормальный метод подклассаsuperПри вызове метода родительского класса this внутри метода указывает на текущий экземпляр подкласса.
  3. Назначьте свойство свойству через 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Указывает на текущий подкласс, а не на экземпляр подкласса.

во всяком случае

  1. superкак функция,super()Представляет конструктор родительского класса внутриthisявляется экземпляром класса.
  2. superкак объект, в обычном методеsuper.Синтаксис указывает на объект-прототип родительского класса, который используется в статических методах.super.Синтаксис заключается в том, чтобы перейти к статическому методу родительского класса, чтобы найти его. Что касаетсяthisУкажите на вопрос, помните одну вещь:Если перед методом добавитьstaticключевое слово, оно означает, что метод не будет унаследован экземпляром, а будет вызываться напрямую через класс, поэтому в статическом методеthisбудет ссылаться только на классы, а не на экземпляры.