Appeler les méthodes statiques à partir des méthodes de classe ES6 régulières

Quelle est la façon standard d'appeler les méthodes statiques? Je peux penser à utiliser constructor ou à utiliser le nom de la classe elle-même, je n'aime pas ce dernier car il ne se sent pas nécessaire. Est l'ancien de la manière recommandée, ou est-il autre chose?

voici un exemple (inventé):

class SomeObject {
  constructor(n){
    this.n = n;
  }

  static print(n){
    console.log(n);
  }

  printN(){
    this.constructor.print(this.n);
  }
}
135
demandé sur Dan Dascalescu 2015-02-20 14:29:12

3 réponses

les deux chemins sont viables, mais ils font des choses différentes quand il s'agit de l'héritage avec une méthode statique dépassée. Choisissez celui dont vous attendez le comportement:

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

se référant à la propriété statique via la classe sera effectivement statique et constamment donner la même valeur. L'utilisation de this.constructor à la place va utiliser la régulation dynamique et se référer à la classe de l'instance actuelle, où la propriété statique pourrait ont l'héritage la valeur, mais pourrait également être remplacé.

cela correspond au comportement de Python, où vous pouvez choisir de vous référer aux propriétés statiques soit via le nom de classe, soit par l'instance self .

si vous vous attendez à ce que les propriétés statiques ne soient pas dépassées (et toujours se référer à celle de la classe actuelle), comme dans Java , utilisez la référence explicite.

161
répondu Bergi 2017-05-23 10:31:33

j'ai trébuché sur ce fil à la recherche de réponse à un cas similaire. Fondamentalement toutes les réponses sont trouvées, mais il est toujours difficile d'en extraire l'essentiel.

types d'accès

Supposons une classe Foo probablement dérivée d'une autre classe(s) avec probablement plus de classes dérivées.

puis accès

  • statiques de la méthode/de lecture de Foo
    • certains remplacée statique méthode/getter:
      • this.method()
      • this.property
    • certains substituée à l'instance méthode/getter:
      • impossible par conception
    • propre non-substituée statique méthode/getter:
      • Foo.method()
      • Foo.property
    • propre non-substituée instance méthode/getter:
      • impossible par conception
  • de l'instance méthode/getter de Foo
    • certains remplacée statique méthode/getter:
      • this.constructor.method()
      • this.constructor.property
    • certains substituée à l'instance méthode/getter:
      • this.method()
      • this.property
    • propre non-substituée statique méthode/getter:
      • Foo.method()
      • Foo.property
    • propre non-substituée instance méthode/getter:
      • impossible par intention à moins d'utiliser une solution de contournement :
        • Foo.prototype.method.call( this )
        • Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);

gardez à l'esprit que l'utilisation de this ne fonctionne pas de cette façon en utilisant des fonctions de flèche ou en invoquant des méthodes/obtenir explicitement lié à la valeur personnalisée.

arrière-plan

  • dans le contexte de la méthode ou du getter d'une instance
    • this se réfère à l'instance actuelle.
    • super se réfère essentiellement à la même instance, mais quelque peu des méthodes d'adressage et des getters écrits dans le contexte d'un courant de classe un s'étend (en utilisant le prototype du prototype de Foo).
    • définition de la classe de l'instance utilisée lors de sa création est disponible par this.constructor .
  • quand dans le contexte d'une méthode statique ou getter il n'y a pas d '"instance actuelle" par intention et ainsi
    • this peut renvoyer directement à la définition de la classe courante.
    • super ne se réfère pas non plus à une instance, mais à des méthodes statiques et des getters écrits dans le contexte d'un courant de classe.

Conclusion

essayez ce code:

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 );
47
répondu cepharum 2017-06-01 13:16:08

si vous prévoyez de faire n'importe quelle sorte d'héritage, alors je recommanderais this.constructor . Cet exemple simple devrait illustrer pourquoi:

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() logera ConstructorSuper Hello ConstructorSuper! à la console
  • test2.callPrint() logera ConstructorSub Hello ConstructorSub! à la console

la classe nommée ne traitera pas correctement l'héritage à moins que vous ne redéfinissiez explicitement chaque fonction qui fait un référence à la classe désignée. Voici un exemple:

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() logera NamedSuper Hello NamedSuper! à la console
  • test4.callPrint() logera NamedSuper Hello NamedSub! à la console

Voir tous les ci-dessus s'exécutant dans Babel REPL .

vous pouvez voir de ceci que test4 pense toujours qu'il est dans la classe super; dans cet exemple, il pourrait ne pas sembler comme une affaire énorme, mais si vous essayez de faire référence à des fonctions de membre qui ont été dépassées ou de nouvelles variables de membre, vous vous trouverez en difficulté.

14
répondu Andrew Odri 2015-02-20 17:36:45