variable nodejs es6 javascript class static ecmascript-6 es6-class

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
  • 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);

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.