Наследование класса javascript ES6, почему нам нужен вызов super() из производного класса

В javascript ES6 при наследовании
если у производного класса есть конструктор, почему обязательно вызывать super из производного конструктора?

несколько неудачных примеров:

. База с конструктором, но производная без вызова super-

 class Base{constructor(){}}
    class Derived{constructor(){}}
    var d = new Derived(); // fails - ReferenceError: this is not defined

person user3359453    schedule 29.12.2016    source источник
comment
попробуйте любой браузер, совместимый с ES6.   -  person user3359453    schedule 29.12.2016


Ответы (2)


... кажется, обязательно иметь функцию конструктора в базовом классе.

Не совсем. Если вы его не предоставили, один будет предоставлен вам движком JavaScript. Таким образом, всегда будет один (в этом смысле он обязателен), но его не нужно кодировать явно.

Когда вы вообще не определяете конструктор, конструктор по умолчанию, предоставляемый движком JavaScript для базового класса, будет выглядеть так:

constructor( ) { }

... и по умолчанию в производном классе будет выглядеть так:

constructor(...args) {
    super(...args);
}

Причина, по которой ваш пример не работает, заключается в том, что Derived имеет явный constructor, но constructor не вызывает super. Вы должны вызывать super из конструктора Derived, если вы явно определяете его.

если у производного класса есть конструктор, почему обязательно вызывать super из производного конструктора?

Потому что вы должны дать суперклассу возможность выполнить любую инициализацию нового объекта, которую он должен выполнить. В противном случае суперкласс не может гарантировать правильную работу, поскольку он может полагаться на инициализацию, выполненную его конструктором.

Так что либо:

  1. Удалите свой constructor из Derived, сделав его похожим на ваш первый пример, чтобы движок JavaScript предоставил конструктор по умолчанию, или

  2. Вызовите super из конструктора Derived.

В комментарии вы спросили:

но если базовый класс не имеет никакого конструктора, он все равно терпит неудачу, если производный класс имеет

Базовый класс всегда имеет конструктор, потому что, если вы его не предоставите (вы сделали это в коде в своем вопросе), предоставляется значение по умолчанию. Так что все равно придется звонить. Хотя его можно указать как необязательный, если ни один из суперклассов не имеет конструктора, отличного от значения по умолчанию, это добавило бы сложности и сделало бы явный конструктор Derived вводящим в заблуждение (без вызова super).

Есть также некоторые механические причины: this не определен, пока вы не вызовете super, но вам разрешено делать что-то до вызова super, поэтому выполнение вызова необходимо для обработки механики this в спецификации.

person T.J. Crowder    schedule 29.12.2016
comment
но если в базовом классе нет конструктора, он все равно терпит неудачу, если производный класс имеет.. - person user3359453; 29.12.2016
comment
@ user3359453: У классов всегда есть конструктор, даже если вы его не предоставляете. У вашего Base есть конструктор (на самом деле, если бы его не было, Base не имело бы значения, потому что Base является конструктором). Из этого естественным образом следует, что подкласс всегда должен вызывать конструктор суперкласса, потому что всегда существует конструктор суперкласса. Теперь это могло указать по-другому, но это сложность, которая не представляет никакой ценности, поэтому я не удивлен, увидев, что они этого не сделали. - person T.J. Crowder; 29.12.2016
comment
@T.J.Crowder, добрый день, мистер Краудер, я большой поклонник ваших работ, прошло много времени с тех пор, как вы дали идеальный ответ на этот вопрос, и я хотел бы задать один вопрос об использовании super() в производном классе. То есть зачем нам использовать super() в конструкторе производного класса? Верно ли, что super() необходимо, чтобы мы могли использовать это в производном классе или...? Пожалуйста, мне очень нужна ваша помощь. Просто зачем нам использовать super() в производном классе. - person Dickens; 31.08.2019
comment
@Dickens - this недоступен в конструкторе подкласса до тех пор, пока после вызова super попытка его использования не является ReferenceError (jsfiddle.net/tjcrowder/05kep9ho). Это связано с тем, что объект создается только непосредственно перед запуском конструктора базового класса (шаг 5.a здесь). Вы должны вызвать super в какой-то момент в конструкторе подкласса, это ReferenceError, если вы этого не сделаете (jsfiddle.net/ tjcrowder/pjdt1m8y). (JavaScript не пошел по пути Java... (продолжение) - person T.J. Crowder; 31.08.2019
comment
(продолжение) вставка вызова по умолчанию для вас, если вы его пропустили.) Вы можете не использовать конструктор подкласса полностью, если хотите; если вы это сделаете, механизм JavaScript создаст для вас такой вариант: constructor(...args) { super(...args); } (шаг 10 здесь). ХТН. - person T.J. Crowder; 31.08.2019

Это не обязательно, но если вы хотите присвоить свойства подклассу, вам нужно вызвать super в конструкторе, чтобы интерпретатор JavaScript знал, какие свойства принадлежат родительскому классу, а какие — подклассу.

Давайте сделаем пример.

В этом случае свойства не назначаются, только методы, поэтому JavaScript автоматически использует пустой конструктор по умолчанию.

class Animal {
  move () {
    console.log('moving');
  }
}

class Dog extends Animal {
  bark () {
    console.log('barking');
  }
}

Если мы хотим присвоить свойства подклассу, нам нужно вызвать super:

class Animal {
  move () {
    console.log('moving');
  }
}

class Dog extends Animal {
  constructor (name) {
    super();
    this.name = name;
  }
  bark () {
    console.log('barking');
  }
}

Причина в том, что в противном случае интерпретатор JavaScript не сможет узнать, принадлежит ли аргумент, переданный конструктору подкласса (name), родительскому классу или подклассу. Так что это нужно программисту, чтобы указать это.

person Pensierinmusica    schedule 06.04.2017
comment
Но почему движок javascript не может скрыть эту деталь реализации? в C-подобных языках вы можете делать что-то вроде this->parent = parent::construct(). почему джаваскрипт? Зачем? - person r3wt; 18.04.2017