É possível estender uma classe no ES6 sem chamar o super
método para invocar a classe pai?
EDIT: A pergunta pode ser enganosa. É o padrão que temos que ligar super()
ou estou faltando alguma coisa?
Por exemplo:
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();
Quando não estou chamando super()
a classe derivada, estou tendo um problema de escopo ->this is not defined
Estou executando isso com iojs --harmony na v2.3.0
javascript
class
inheritance
ecmascript-6
xhallix
fonte
fonte
Respostas:
As regras para as classes ES2015 (ES6) basicamente se resumem a:
this
não pode ser usado até quesuper
seja chamado.super
se forem subclasses, ou devem retornar explicitamente algum objeto para substituir aquele que não foi inicializado.Isso se resume a duas seções importantes da especificação ES2015.
A seção 8.1.1.3.4 define a lógica para decidir o que
this
está na função. A parte importante para as classes é que é possívelthis
estar em um"uninitialized"
estado e, quando nesse estado, tentar usarthis
lançará uma exceção.Seção 9.2.2 ,
[[Construct]]
que define o comportamento das funções chamadas vianew
ousuper
. Ao chamar um construtor de classe base,this
é inicializado na etapa 8 de[[Construct]]
, mas para todos os outros casos,this
não é inicializado. No final da construção,GetThisBinding
é chamado, portanto, sesuper
ainda não tiver sido chamado (inicializando assimthis
), ou um objeto de substituição explícito não for retornado, a linha final da chamada do construtor lançará uma exceção.fonte
super()
?super()
o construtor?return Object.create(new.target.prototype, …)
para evitar chamar o super construtor.Houve várias respostas e comentários afirmando que
super
DEVE ser a primeira linha dentroconstructor
. Isso está simplesmente errado. A resposta @loganfsmyth tem as referências exigidas dos requisitos, mas se resume a:O
extends
construtor Inheriting ( ) deve chamarsuper
antes de usarthis
e antes de retornar, mesmo sethis
não for usadoVeja o fragmento abaixo (funciona no Chrome ...) para ver por que pode fazer sentido ter instruções (sem usar
this
) antes de chamarsuper
.fonte
"See fragment below (works in Chrome...)"
abra o console do desenvolvedor Chrome e clique em "código Run trecho":Uncaught ReferenceError: this is not defined
. Claro, você pode usar métodos no construtor antes,super()
mas não pode usar métodos da classe antes!this
antessuper()
(seu código prova isso) não tem nada a ver com a especificação imediata, mas com a implementação de javascript. Então, você tem que chamar 'super' antes de 'isso'.super
, e você estava afirmando que é ilegal usarthis
antes de ligarsuper
. Estamos ambos certos, apenas não nos entendíamos :-) (E essa exceção foi intencional, para mostrar o que não é legal - até chamei a propriedade de 'WillFail')A nova sintaxe da classe es6 é apenas uma outra notação para as "antigas" classes es5 "com protótipos. Portanto, você não pode instanciar uma classe específica sem definir seu protótipo (a classe base).
É como colocar queijo no sanduíche sem prepará-lo. Também não se pode colocar queijo antes de fazer o sanduíche, então ...
... usar a
this
palavra-chave antes de chamar a superclasse comsuper()
também não é permitido.Se você não especificar um construtor para uma classe base, a seguinte definição será usada:
Para classes derivadas, o seguinte construtor padrão é usado:
EDIT: Encontrado em
developer.mozilla.org
:Fonte
fonte
this
não é usado. 2. JS não é um sanduíche e no ES5 você sempre pode usarthis
, mesmo antes de chamar qualquer outra função que desejar (que pode ou não definir a propriedade de suplemento)this
também ?! 2. Minha classe JS representa um sanduíche, e no ES6 você nem sempre pode usarthis
. Estou apenas tentando explicar as classes es6 (com uma metáfora), e ninguém precisa desses comentários destrutivos / desnecessários.Só me inscrevi para postar essa solução pois as respostas aqui não me satisfazem minimamente, pois na verdade existe uma maneira simples de contornar isso. Ajuste seu padrão de criação de classe para sobrescrever sua lógica em um sub-método enquanto usa apenas o super construtor e encaminhe os argumentos do construtor para ele.
Como em, você não cria um construtor em suas subclasses per se, mas apenas faz referência a um método que é sobrescrito na respectiva subclasse.
Isso significa que você se libertou da funcionalidade do construtor imposta a você e se absteve de um método regular - que pode ser substituído e não impõe super () ao se permitir a escolha se, onde e como deseja chamar super (totalmente opcional) por exemplo:
Felicidades!
fonte
Você pode omitir super () em sua subclasse, se omitir totalmente o construtor em sua subclasse. Um construtor padrão 'oculto' será incluído automaticamente em sua subclasse. No entanto, se você incluir o construtor em sua subclasse, super () deve ser chamado nesse construtor.
Leia isto para mais informações.
fonte
A resposta por justyourimage é a maneira mais fácil, mas seu exemplo é um pouco inchado. Aqui está a versão genérica:
Não estenda o real
constructor()
, apenas use o falso_constructor()
para a lógica de instanciação.Observe que esta solução torna a depuração irritante porque você precisa adotar um método extra para cada instanciação.
fonte
Experimentar:
Demo
fonte
A constructor *can* use the super keyword to call the constructor of a parent class.
então eu diria que aguarde o lançamento do ES6Eu recomendaria usar OODK-JS se você pretende desenvolver os seguintes conceitos OOP.
fonte
Solução simples: acho que não há necessidade de explicação.
fonte
@Bergi mencionou
new.target.prototype
, mas eu estava procurando um exemplo concreto provando que você pode acessarthis
(ou melhor, a referência ao objeto com o qual o código do cliente está criandonew
, veja abaixo) sem ter que chamarsuper()
.Falar é barato, mostre-me o código ... Então, aqui está um exemplo:
O que resultará em:
Assim você pode ver que estamos efetivamente criando um objeto do tipo
B
(a classe filha), que também é um objeto do tipoA
(sua classe pai) e nochildMethod()
da criançaB
, temosthis
apontando para o objetoobj
que criamos no B deconstructor
comObject.create(new.target.prototype)
.E tudo isso sem se preocupar com
super
nada.Isso aproveita o fato de que em JS a
constructor
pode retornar um objeto completamente diferente quando o código do cliente constrói uma nova instância comnew
.Espero que isso ajude alguém.
fonte