Если я могу вызвать родительские методы через это, то зачем использовать super в 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, которое используется для доступа к членам родительского класса в дочернем классе. Но я могу очень легко получить доступ к членам родительского класса в дочернем классе, используя this:

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

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

Property 1 Property 2

Теперь давайте сделаем то же самое, используя super вместо this в дочернем классе 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, зачем нам его использовать? Кто-нибудь может рассказать простыми словами на примере?


person Community    schedule 01.10.2018    source источник


Ответы (2)


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

Это в основном используется при переопределении реализации родителя, но все же при желании вызвать реализацию родителя:

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

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

    bar() {
        super.bar();
        console.log(42);
    }
}
person deceze♦    schedule 01.10.2018
comment
почему вы использовали constructor() {super();console.log(42); в дочернем классе какой смысл в этом в дочернем классе? - person ; 01.10.2018
comment
Он выполняет родительский конструктор, а также делает что-то в своем собственном конструкторе. Этот конкретный пример, конечно, не представляет интереса, он просто демонстрирует этот принцип. - person deceze♦; 01.10.2018
comment
Даже мы можем вызвать super.bar() в классе Baz без constructor() {super();console.log(42); , тогда зачем использовать constructor() {super();console.log(42); не могли бы вы уточнить? - person ; 01.10.2018
comment
Это независимые примеры. Он показывает переопределение конструктора и вызов родительского конструктора, а также показывает переопределение bar и вызов родительского bar. - person deceze♦; 01.10.2018

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

 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");
 }
}
person Jonas Wilms    schedule 01.10.2018
comment
его нет или больше? - person ; 01.10.2018