javascript - es6 - nodejs class
Llamar a métodos estáticos desde métodos de clase ES6 normales (3)
Ambas formas son viables, pero hacen cosas diferentes cuando se trata de herencia con un método estático anulado. Elige el comportamiento que esperas:
class Super {
static whoami() {
return "Super";
}
lognameA() {
console.log(Super.whoami());
}
lognameB() {
console.log(this.constructor.whoami());
}
}
class Sub extends Super {
static whoami() {
return "Sub";
}
}
new Sub().lognameA(); // Super
new Sub().lognameB(); // Sub
Hacer referencia a la propiedad estática a través de la clase será realmente estática y constantemente dará el mismo valor.
El uso de
this.constructor
en
this.constructor
lugar usará el despacho dinámico y se referirá a la clase de la instancia actual, donde la propiedad estática
podría
tener el valor heredado pero también podría anularse.
Esto coincide con el comportamiento de Python, donde puede elegir hacer referencia a propiedades estáticas ya sea a través del nombre de la clase o de la instancia
self
.
Si espera que las propiedades estáticas no se anulen (y siempre se refieren a la de la clase actual), como en Java , use la referencia explícita.
¿Cuál es la forma estándar de llamar a métodos estáticos?
Puedo pensar en usar el
constructor
o el nombre de la clase en sí, no me gusta este último ya que no me parece necesario.
¿Es la primera la forma recomendada o hay algo más?
Aquí hay un ejemplo (artificial):
class SomeObject {
constructor(n){
this.n = n;
}
static print(n){
console.log(n);
}
printN(){
this.constructor.print(this.n);
}
}
Me topé con este hilo en busca de una respuesta a un caso similar. Básicamente se encuentran todas las respuestas, pero aún es difícil extraer lo esencial de ellas.
Tipos de acceso
Suponga que una clase Foo probablemente deriva de alguna otra clase (s) con probablemente más clases derivadas de ella.
Luego accediendo
-
del
método
estático
/ getter de Foo
-
algunos métodos
estáticos
/ getter probablemente
anulados
:
-
this.method()
-
this.property
-
-
algún método / getter de
instancia
probablemente
anulado
:
- imposible por diseño
-
propio método / captador
estático no anulado
:
-
Foo.method()
-
Foo.property
-
-
propio método / getter de
instancia no anulada
:
- imposible por diseño
-
algunos métodos
estáticos
/ getter probablemente
anulados
:
-
del
método de
instancia
/ getter de Foo
-
algunos métodos
estáticos
/ getter probablemente
anulados
:
-
this.constructor.method()
-
this.constructor.property
-
-
algún método / getter de
instancia
probablemente
anulado
:
-
this.method()
-
this.property
-
-
propio método / captador
estático no anulado
:
-
Foo.method()
-
Foo.property
-
-
propio método / getter de
instancia no anulada
:
-
no es posible por intención a menos que use alguna solución alternativa
:
-
Foo.prototype.method.call( this )
-
Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);
-
-
no es posible por intención a menos que use alguna solución alternativa
:
-
algunos métodos
estáticos
/ getter probablemente
anulados
:
Tenga en cuenta que usar
this
no funciona de esta manera al usar funciones de flecha o invocar métodos / captadores vinculados explícitamente a un valor personalizado.
Antecedentes
-
Cuando está en contexto del método o getter de una instancia
-
this
se refiere a la instancia actual. -
super
está refiriendo básicamente a la misma instancia, pero de alguna manera se está ampliando los métodos y captadores escritos en el contexto de alguna clase actual (usando el prototipo del prototipo de Foo). -
La definición de la clase de instancia utilizada para crearla está disponible según
this.constructor
.
-
-
Cuando en el contexto de un método estático o getter no hay una "instancia actual" por intención y así
-
this
está disponible para referirse directamente a la definición de clase actual. -
super
tampoco se refiere a alguna instancia, sino que se está extendiendo a métodos estáticos y captadores escritos en el contexto de alguna clase actual.
-
Conclusión
Prueba este código:
class A {
constructor( input ) {
this.loose = this.constructor.getResult( input );
this.tight = A.getResult( input );
console.log( this.scaledProperty, Object.getOwnPropertyDescriptor( A.prototype, "scaledProperty" ).get.call( this ) );
}
get scaledProperty() {
return parseInt( this.loose ) * 100;
}
static getResult( input ) {
return input * this.scale;
}
static get scale() {
return 2;
}
}
class B extends A {
constructor( input ) {
super( input );
this.tight = B.getResult( input ) + " (of B)";
}
get scaledProperty() {
return parseInt( this.loose ) * 10000;
}
static get scale() {
return 4;
}
}
class C extends B {
constructor( input ) {
super( input );
}
static get scale() {
return 5;
}
}
class D extends C {
constructor( input ) {
super( input );
}
static getResult( input ) {
return super.getResult( input ) + " (overridden)";
}
static get scale() {
return 10;
}
}
let instanceA = new A( 4 );
console.log( "A.loose", instanceA.loose );
console.log( "A.tight", instanceA.tight );
let instanceB = new B( 4 );
console.log( "B.loose", instanceB.loose );
console.log( "B.tight", instanceB.tight );
let instanceC = new C( 4 );
console.log( "C.loose", instanceC.loose );
console.log( "C.tight", instanceC.tight );
let instanceD = new D( 4 );
console.log( "D.loose", instanceD.loose );
console.log( "D.tight", instanceD.tight );
Si planea hacer algún tipo de herencia, le recomendaría
this.constructor
.
Este simple ejemplo debería ilustrar por qué:
class ConstructorSuper {
constructor(n){
this.n = n;
}
static print(n){
console.log(this.name, n);
}
callPrint(){
this.constructor.print(this.n);
}
}
class ConstructorSub extends ConstructorSuper {
constructor(n){
this.n = n;
}
}
let test1 = new ConstructorSuper("Hello ConstructorSuper!");
console.log(test1.callPrint());
let test2 = new ConstructorSub("Hello ConstructorSub!");
console.log(test2.callPrint());
-
test1.callPrint()
registraráConstructorSuper Hello ConstructorSuper!
a la consola -
test2.callPrint()
registraráConstructorSub Hello ConstructorSub!
a la consola
La clase nombrada no se ocupará muy bien de la herencia a menos que redefina explícitamente cada función que haga referencia a la Clase nombrada. Aquí hay un ejemplo:
class NamedSuper {
constructor(n){
this.n = n;
}
static print(n){
console.log(NamedSuper.name, n);
}
callPrint(){
NamedSuper.print(this.n);
}
}
class NamedSub extends NamedSuper {
constructor(n){
this.n = n;
}
}
let test3 = new NamedSuper("Hello NamedSuper!");
console.log(test3.callPrint());
let test4 = new NamedSub("Hello NamedSub!");
console.log(test4.callPrint());
-
test3.callPrint()
registraráNamedSuper Hello NamedSuper!
a la consola -
test4.callPrint()
registraráNamedSuper Hello NamedSub!
a la consola
Ver todo lo anterior en ejecución en Babel REPL .
Puedes ver de esto que
test4
todavía piensa que está en la
test4
;
En este ejemplo, puede que no parezca un gran problema, pero si está tratando de hacer referencia a funciones de miembros que han sido anuladas o nuevas variables de miembros, se encontrará en problemas.