Можно ли расширить класс в ES6 без вызова super
метода для вызова родительского класса?
EDIT: вопрос может вводить в заблуждение. Это стандарт, по которому мы должны звонить, super()
или я что-то упускаю?
Например:
class Character {
constructor(){
console.log('invoke character');
}
}
class Hero extends Character{
constructor(){
super(); // exception thrown here when not called
console.log('invoke hero');
}
}
var hero = new Hero();
Когда я не вызываю super()
производный класс, у меня возникает проблема с областью видимости ->this is not defined
Я запускаю это с помощью iojs --harmony в v2.3.0
javascript
class
inheritance
ecmascript-6
Xhallix
источник
источник
Ответы:
Правила для классов ES2015 (ES6) в основном сводятся к:
this
нельзя использовать доsuper
вызова.super
если они являются подклассами, или они должны явно возвращать какой-либо объект, чтобы заменить тот, который не был инициализирован.Это сводится к двум важным разделам спецификации ES2015.
Раздел 8.1.1.3.4 определяет логику, чтобы решить, что
this
находится в функции. Важная часть для классов заключается в том, что они могутthis
находиться в"uninitialized"
состоянии, и когда в этом состоянии попытка использованияthis
вызовет исключение.Раздел 9.2.2 , в
[[Construct]]
котором определяется поведение функций, вызываемых черезnew
илиsuper
. При вызове конструктора базового классаthis
инициализируется на шаге № 8[[Construct]]
, но во всех остальных случаяхthis
не инициализируется. В конце конструкцииGetThisBinding
вызывается, поэтому, если онsuper
еще не был вызван (таким образом, инициализированthis
) или явный объект замены не был возвращен, последняя строка вызова конструктора вызовет исключение.источник
super()
?super()
конструктора?return Object.create(new.target.prototype, …)
чтобы избежать вызова суперконструктора.Было несколько ответов и комментариев, в которых говорилось, что
super
ДОЛЖНА быть первой строчкой внутриconstructor
. Это просто неправильно. Ответ @loganfsmyth содержит необходимые ссылки на требования, но они сводятся к следующему:extends
Конструктор Inheriting ( ) должен вызыватьsuper
перед использованиемthis
и перед возвратом, даже еслиthis
не используетсяСм. Фрагмент ниже (работает в Chrome ...), чтобы понять, почему может иметь смысл иметь операторы (без использования
this
) перед вызовомsuper
.источник
"See fragment below (works in Chrome...)"
откройте консоль разработчика Chrome и нажмите на кнопку «Выполнить фрагмент кода»:Uncaught ReferenceError: this is not defined
. Конечно, вы можете использовать методы в конструкторе раньше,super()
но вы не можете использовать методы из класса раньше!this
раньшеsuper()
(ваш код доказывает это), не имеет ничего общего со спецификацией непосредственно, а с реализацией javascript. Итак, вы должны назвать «супер» перед «этим».super
, а вы заявляли, что использоватьthis
перед вызовом незаконноsuper
. Мы оба правы, просто не понимали друг друга :-) (И это исключение было намеренным, чтобы показать, что не является законным - я даже назвал свойство WillFail)Синтаксис нового класса es6 - это всего лишь другая нотация для «старых» классов es5 с прототипами. Следовательно, вы не можете создать конкретный класс, не задав его прототип (базовый класс).
Это все равно, что положить сыр на бутерброд, не приготовив его. Также нельзя класть сыр перед приготовлением бутерброда, так что ...
... использование
this
ключевого слова перед вызовом суперкласса такжеsuper()
запрещено.Если вы не укажете конструктор для базового класса, используется следующее определение:
Для производных классов используется следующий конструктор по умолчанию:
РЕДАКТИРОВАТЬ: нашел это
developer.mozilla.org
:Источник
источник
this
вообще не используется. 2. JS - это не бутерброд, и в ES5 вы всегда можете использоватьthis
, даже перед вызовом любой другой функции, которая вам нравится (которая может определять или не определять свойство дополнения)this
?! 2. Мой класс JS представляет собой бутерброд, и в ES6 вы не всегда можете его использоватьthis
. Я просто пытаюсь объяснить классы es6 (метафорой), и никому не нужны такие деструктивные / ненужные комментарии.Просто зарегистрировался, чтобы опубликовать это решение, поскольку ответы здесь меня нисколько не удовлетворяют, поскольку на самом деле есть простой способ обойти это. Отрегулируйте шаблон создания класса, чтобы перезаписать вашу логику в подметоде, используя только суперконструктор, и перенаправить ему аргументы конструктора.
Как и в случае, вы не создаете конструктор в своих подклассах как таковых, а только ссылку на метод, который переопределяется в соответствующем подклассе.
Это означает, что вы освобождаете себя от навязываемой вам функциональности конструктора и воздерживаетесь от обычного метода, который может быть переопределен и не применяет super (), если вы позволяете себе выбирать, где и как вы хотите вызвать super (полностью необязательно) например:
ура!
источник
Вы можете опустить super () в своем подклассе, если вы полностью опустите конструктор в своем подклассе. «Скрытый» конструктор по умолчанию будет автоматически включен в ваш подкласс. Однако, если вы все же включаете конструктор в свой подкласс, в этом конструкторе должен вызываться super ().
Прочтите это для получения дополнительной информации.
источник
Ответ justyourimage - самый простой способ, но его пример немного раздут. Вот общая версия:
Не расширяйте реальное
constructor()
, просто используйте подделку_constructor()
для логики создания экземпляра.Обратите внимание, что это решение делает отладку раздражающей, потому что вам нужно использовать дополнительный метод для каждого экземпляра.
источник
Пытаться:
Demo
источник
A constructor *can* use the super keyword to call the constructor of a parent class.
поэтому я бы сказал, дождитесь выпуска ES6Я бы рекомендовал использовать OODK-JS, если вы собираетесь разрабатывать следующие концепции ООП.
источник
Простое решение: я думаю, что объяснения очевидны.
источник
@Bergi упомянул
new.target.prototype
, но я искал конкретный пример, доказывающий, что вы можете получить доступthis
(или, лучше, ссылку на объект, с которым создается клиентский кодnew
, см. Ниже) без необходимости вызыватьsuper()
вообще .Обсуждение дешево, покажите код ... Итак, вот пример:
Что выведет:
Итак, вы можете видеть, что мы эффективно создаем объект типа
B
(дочерний класс), который также является объектом типаA
(его родительский класс), и внутриchildMethod()
дочернегоB
мыthis
указываем на объект,obj
который мы создали в Bconstructor
с помощьюObject.create(new.target.prototype)
.И все это совершенно безразлично
super
.Это использует тот факт, что в JS a
constructor
может возвращать совершенно другой объект, когда клиентский код создает новый экземпляр сnew
.Надеюсь, это кому-то поможет.
источник