javascript - tipos - super js
¿Cómo extender una clase sin tener que usar super en ES6? (9)
Acabo de registrarme para publicar esta solución, ya que las respuestas aquí no me satisfacen lo más mínimo, ya que en realidad hay una forma simple de evitar esto. Ajuste su patrón de creación de clase para sobrescribir su lógica en un submétodo mientras usa solo el superconstructor y reenvíele los argumentos del constructor.
Como en el caso, no crea un constructor en sus subclases per se, sino solo una referencia a un método que se anula en la subclase respectiva.
Eso significa que se libera de la funcionalidad del constructor que se le aplica y se abstiene de un método regular , que se puede anular y no impone super () si se permite elegir si, dónde y cómo desea llamar super (totalmente opcional) por ejemplo:
super.ObjectConstructor(...)
class Observable {
constructor() {
return this.ObjectConstructor(arguments);
}
ObjectConstructor(defaultValue, options) {
this.obj = { type: "Observable" };
console.log("Observable ObjectConstructor called with arguments: ", arguments);
console.log("obj is:", this.obj);
return this.obj;
}
}
class ArrayObservable extends Observable {
ObjectConstructor(defaultValue, options, someMoreOptions) {
this.obj = { type: "ArrayObservable" };
console.log("ArrayObservable ObjectConstructor called with arguments: ", arguments);
console.log("obj is:", this.obj);
return this.obj;
}
}
class DomainObservable extends ArrayObservable {
ObjectConstructor(defaultValue, domainName, options, dependent1, dependent2) {
this.obj = super.ObjectConstructor(defaultValue, options);
console.log("DomainObservable ObjectConstructor called with arguments: ", arguments);
console.log("obj is:", this.obj);
return this.obj;
}
}
var myBasicObservable = new Observable("Basic Value", "Basic Options");
var myArrayObservable = new ArrayObservable("Array Value", "Array Options", "Some More Array Options");
var myDomainObservable = new DomainObservable("Domain Value", "Domain Name", "Domain Options", "Dependency A", "Depenency B");
¡salud!
¿Es posible extender una clase en ES6 sin llamar al método
super
para invocar la clase padre?
EDITAR: La pregunta puede ser engañosa.
¿Es el estándar 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 estoy llamando a
super()
en la clase derivada, obtengo un problema de alcance ->
this is not defined
Estoy ejecutando esto con iojs --harmony en v2.3.0
Ha habido múltiples respuestas y comentarios que indican que
super
DEBE
ser la primera línea dentro del
constructor
.
Eso simplemente está mal.
La respuesta @loganfsmyth tiene las referencias requeridas de los requisitos, pero se reduce a:
El constructor heredado (se
extends
)
debe
llamar a
super
antes de usar
this
y antes de regresar, incluso si no se usa
Vea el fragmento a continuación (funciona en Chrome ...) para ver por qué podría tener sentido tener declaraciones (sin usar
this
) antes de llamar a
super
.
''use strict'';
var id = 1;
function idgen() {
return ''ID:'' + id++;
}
class Base {
constructor(id) {
this.id = id;
}
toString() { return JSON.stringify(this); }
}
class Derived1 extends Base {
constructor() {
var anID = idgen() + '':Derived1'';
super(anID);
this.derivedProp = this.baseProp * 2;
}
}
alert(new Derived1());
La nueva sintaxis de la clase es6 es solo otra notación para "antiguas" 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 prepararlo. Tampoco puedes poner queso antes de hacer el sándwich, así que ...
... el uso de
this
palabra clave antes de llamar a la superclase con
super()
tampoco está permitido.
// valid: Add cheese after making the sandwich
class CheeseSandwich extend Sandwich {
constructor() {
super();
this.supplement = "Cheese";
}
}
// invalid: Add cheese before making sandwich
class CheeseSandwich extend Sandwich {
constructor() {
this.supplement = "Cheese";
super();
}
}
// invalid: Add cheese without making sandwich
class CheeseSandwich extend Sandwich {
constructor() {
this.supplement = "Cheese";
}
}
Si no especifica un constructor para una clase base, se utiliza la siguiente definición:
constructor() {}
Para las clases derivadas, se utiliza el siguiente constructor predeterminado:
constructor(...args) {
super(...args);
}
EDITAR: Encontré esto en
developer.mozilla.org
:
When used in a constructor, the super keyword appears alone and must be used before the this keyword can be used.
La respuesta de justyourimage es la forma más fácil, pero su ejemplo es un poco hinchado. Aquí está la versión genérica:
class Base {
constructor(){
return this._constructor(...arguments);
}
_constructor(){
// just use this as the constructor, no super() restrictions
}
}
class Ext extends Base {
_constructor(){ // _constructor is automatically called, like the real constructor
this.is = "easy"; // no need to call super();
}
}
No extienda el
constructor()
real
constructor()
, solo use el falso
_constructor()
para la lógica de instanciación.
Tenga en cuenta que esta solución hace que la depuración sea molesta porque tiene que ingresar a un método adicional para cada instanciación.
Las reglas para las clases ES2015 (ES6) básicamente se reducen a:
-
En un constructor de clase hijo,
this
no se puede usar hasta que se llamesuper
. -
Los constructores de clase ES6 DEBEN llamar a
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é es
this
en la función.
La parte importante para las clases es que es posible que
this
esté en un estado
"uninitialized"
, y cuando esté en este estado, intentar usar
this
arrojará una excepción.
Sección
9.2.2
,
[[Construct]]
, que define el comportamiento de las funciones llamadas a través de
new
o
super
.
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, se llama a
GetThisBinding
, por lo que si todavía no se ha llamado a
super
(inicializando
this
), o no se ha devuelto un objeto de reemplazo explícito, la línea final de la llamada del constructor arrojará una excepción.
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, se debe llamar a super () en ese constructor.
class A{
constructor(){
this.name = ''hello'';
}
}
class B extends A{
constructor(){
// console.log(this.name); // ReferenceError
super();
console.log(this.name);
}
}
class C extends B{} // see? no super(). no constructor()
var x = new B; // hello
var y = new C; // hello
Lea this para más información.
Recomendaría usar OODK-JS si tiene la intención de desarrollar los siguientes conceptos de OOP.
OODK(function($, _){
var Character = $.class(function ($, µ, _){
$.public(function __initialize(){
$.log(''invoke character'');
});
});
var Hero = $.extends(Character).class(function ($, µ, _){
$.public(function __initialize(){
$.super.__initialize();
$.log(''invoke hero'');
});
});
var hero = $.new(Hero);
});
Solución simple: creo que está claro, no hay necesidad de explicación.
class ParentClass() {
constructor(skipConstructor = false) { // default value is false
if(skipConstructor) return;
// code here only gets executed when ''super()'' is called with false
}
}
class SubClass extends ParentClass {
constructor() {
super(true) // true for skipping ParentClass''s constructor.
// code
}
}
Tratar:
class Character {
constructor(){
if(Object.getPrototypeOf(this) === Character.prototype){
console.log(''invoke character'');
}
}
}
class Hero extends Character{
constructor(){
super(); // throws exception when not called
console.log(''invoke hero'');
}
}
var hero = new Hero();
console.log(''now let/'s invoke Character'');
var char = new Character();