Если я могу вызывать родительские методы через это, то зачем использовать супер в ES6?

Допустим, у нас есть класс ABC:

class ABC{
    constructor(param1, param2){
        this.prop1 = param1;
        this.prop2 = param2;
    }
    ABCMethod1(){
        console.log(this.prop1 + ' ' + this.prop2);
    }
}

И еще один класс XYZ, который расширяет класс ABC:

class XYZ extends ABC{
    XYZMethod1(){
        this.ABCMethod1();
    }
}

Итак, ES6 представил новое ключевое слово super, которое используется для доступа к членам родительского класса в дочернем классе. Но я могу легко получить доступ к членам родительского класса в дочернем классе с помощью этого:

var myObject = new XYZ('Property 1','Property 2');
myObject.XYZMethod1();

Который печатает следующее в консоли браузера:

Property 1 Property 2

Теперь давайте сделаем то же самое, используя super вместо этого в дочернем классе XYZ:

class XYZ extends ABC{
    XYZMethod1(){
        super.ABCMethod1();
    }
}

Теперь давайте снова вызовем XYZmethod1(), чтобы увидеть, каков будет результат:

var myObject = new XYZ('Property 1','Property 2');
myObject.XYZMethod1();

Который печатает следующее в консоли браузера:

Property 1 Property 2

Результат: и this, и super возвращают одинаковый результат Property 1 Property 2 в консоли. Итак, если мы можем получить доступ к родительским методам, используя this, тогда каково назначение super в ES6, зачем нам его использовать? Кто-нибудь может сказать простыми словами с примером?

2 ответа

Решение

Если у вас есть тот же метод, определенный в родительском и дочернем классе, super явно позволяет получить реализацию родителя. Да, Javascript (и практически все другие языки ООП) будут проходить цепочку прототипов вверх, чтобы найти свойства, определенные для родителей, поэтому вам не нужно вызывать метод родителя. На самом деле, вы не обязательно знаете, сколько слоев определено для метода, поэтому было бы безумно нуждаться в нем. Он нужен только для устранения неоднозначности, когда существует более одной возможной реализации (текущий класс или его родитель).

Это главным образом используется при переопределении реализации родителя, но все еще хочет вызвать реализацию родителя:

class Foo {
    constructor() {}
    bar() {}
}

class Baz {
    constructor() {
        super();
        console.log(42);
    }

    bar() {
        super.bar();
        console.log(42);
    }
}

Это облегчает вызов конструктора суперкласса:

 constructor() {
   super("param 1", "param 2");
 }

И это облегчает вызов метода суперкласса, если он переопределяется подклассом (с тем же именем):

 class Animal {
  move() {
   console.log("moves");
  }
}

class Bird extends Animal {
 move() {
  super.move();
  // this.move() would end into endless recursion
  console.log("flies");
 }
}
Другие вопросы по тегам