¿Es posible extender una clase en ES6 sin llamar al super
método para invocar la clase principal?
EDITAR: La pregunta puede ser engañosa. ¿Es el estándar al que tenemos que llamar super()
o me falta algo?
Por ejemplo:
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();
Cuando no llamo super()
a la clase derivada, tengo un problema de alcance ->this is not defined
Estoy ejecutando esto con iojs --harmony en v2.3.0
javascript
class
inheritance
ecmascript-6
xhallix
fuente
fuente
Respuestas:
Las reglas para las clases de ES2015 (ES6) básicamente se reducen a:
this
no se puede usar hasta quesuper
se llame.super
si son subclases, o deben devolver explícitamente algún objeto para tomar el lugar del que no se inicializó.Esto se reduce a dos secciones importantes de la especificación ES2015.
La sección 8.1.1.3.4 define la lógica para decidir qué
this
hay en la función. La parte importante para las clases es que es posiblethis
estar en un"uninitialized"
estado, y cuando se está en este estado, intentar usarthis
arrojará una excepción.Sección 9.2.2 ,
[[Construct]]
que define el comportamiento de funciones llamadas víanew
osuper
. Cuando se llama a un constructor de clase base,this
se inicializa en el paso # 8 de[[Construct]]
, pero para todos los demás casos,this
no se inicializa. Al final de la construcción,GetThisBinding
se llama, por lo que sisuper
aún no se ha llamado (por lo tanto, se está inicializandothis
), o no se ha devuelto un objeto de reemplazo explícito, la línea final de la llamada al constructor arrojará una excepción.fuente
super()
?super()
al constructor?return Object.create(new.target.prototype, …)
para evitar llamar al superconstructor.Ha habido múltiples respuestas y comentarios indicando que
super
DEBE ser la primera línea adentroconstructor
. Eso es simplemente incorrecto. La respuesta de @loganfsmyth tiene las referencias requeridas de los requisitos, pero se reduce a:El
extends
constructor Inheriting ( ) debe llamarsuper
antes de usarthis
y antes de regresar, incluso sithis
no se usaVea el fragmento a continuación (funciona en Chrome ...) para ver por qué podría tener sentido tener declaraciones (sin usar
this
) antes de llamarsuper
.fuente
"See fragment below (works in Chrome...)"
abrir la consola para desarrolladores de Chrome y haga clic en "Ejecutar código de fragmento":Uncaught ReferenceError: this is not defined
. Claro, puedes usar métodos en el constructor antes, ¡super()
pero no puedes usar métodos de la clase antes!this
antessuper()
(su código lo prueba) no tiene nada que ver con la especificación de inmediato, sino con la implementación de javascript. Entonces, debes llamar a 'super' antes de 'esto'.super
, y tú estabas diciendo que es ilegal usarlothis
antes de llamarsuper
. Ambos tenemos razón, simplemente no nos entendimos :-) (Y esa excepción fue intencional, para mostrar lo que no es legal, incluso llamé a la propiedad 'WillFail')La nueva sintaxis de la clase es6 es sólo otra notación para las "viejas" clases "es5" con prototipos. Por lo tanto, no puede crear una instancia de una clase específica sin establecer su prototipo (la clase base).
Eso es como poner queso en tu sándwich sin hacerlo. Además, no puedes poner queso antes de hacer el sándwich, así que ...
... tampoco se permite usar una
this
palabra clave antes de llamar a la superclase consuper()
.Si no especifica un constructor para una clase base, se usa la siguiente definición:
Para las clases derivadas, se utiliza el siguiente constructor predeterminado:
EDITAR: Encontré esto en
developer.mozilla.org
:Fuente
fuente
this
no se usa en absoluto. 2. JS no es un sándwich, y en ES5 siempre puede usarlothis
, incluso antes de llamar a cualquier otra función que desee (que podría o no definir la propiedad del suplemento)this
también ?! 2. Mi clase JS representa un sándwich y en ES6 no siempre se puede usarthis
. Solo estoy tratando de explicar las clases de es6 (con una metáfora), y nadie necesita comentarios tan destructivos / innecesarios.Me acabo de registrar para publicar esta solución, ya que las respuestas aquí no me satisfacen en lo más mínimo, ya que en realidad hay una forma simple de evitar esto. Ajuste su patrón de creación de clases para sobrescribir su lógica en un submétodo mientras usa solo el superconstructor y le envía los argumentos del constructor.
Como en, no crea un constructor en sus subclases per se, sino solo una referencia a un método que se reemplaza en la subclase respectiva.
Eso significa que se libera de la funcionalidad de constructor que se le impone y se abstiene de usar un método regular , que puede ser anulado y no impone super () si se permite elegir si, dónde y cómo desea llamar a super (completamente opcional) por ejemplo:
¡salud!
fuente
Puede omitir super () en su subclase, si omite el constructor por completo en su subclase. Un constructor predeterminado 'oculto' se incluirá automáticamente en su subclase. Sin embargo, si incluye el constructor en su subclase, debe llamarse super () en ese constructor.
Lea esto para obtener más información.
fuente
La respuesta con justyourimage es la forma más fácil, pero su ejemplo es un poco hinchado. Aquí está la versión genérica:
No extiendas lo real
constructor()
, solo usa lo falso_constructor()
para la lógica de creación de instancias.Tenga en cuenta que esta solución hace que la depuración sea molesta porque debe ingresar a un método adicional para cada instanciación.
fuente
Tratar:
Demo
fuente
A constructor *can* use the super keyword to call the constructor of a parent class.
entonces diría que espere el lanzamiento de ES6Recomendaría usar OODK-JS si tiene la intención de desarrollar los siguientes conceptos de programación orientada a objetos.
fuente
Solución simple: creo que está claro que no hay necesidad de explicación.
fuente
@Bergi mencionó
new.target.prototype
, pero estaba buscando un ejemplo concreto que demuestre que puede accederthis
(o mejor, la referencia al objeto con el que está creando el código del clientenew
, ver más abajo) sin tener que llamarsuper()
en absoluto.Hablar es barato, enséñame el código ... Así que aquí tienes un ejemplo:
Que dará como resultado:
Entonces, puede ver que estamos creando efectivamente un objeto de tipo
B
(la clase secundaria) que también es un objeto de tipoA
(su clase principal) y dentrochildMethod()
del elemento secundarioB
tenemosthis
apuntando al objetoobj
que creamos en Bconstructor
conObject.create(new.target.prototype)
.Y todo esto sin importarle
super
nada.Esto aprovecha el hecho de que en JS a
constructor
puede devolver un objeto completamente diferente cuando el código del cliente construye una nueva instancia connew
.Espero que esto ayude a alguien.
fuente