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);
}
}
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.
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
- certains remplacée statique méthode/getter:
- 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);
-
- impossible par intention à moins d'utiliser une solution de contournement :
- certains remplacée statique méthode/getter:
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 );
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()
logeraConstructorSuper Hello ConstructorSuper!
à la console -
test2.callPrint()
logeraConstructorSub 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()
logeraNamedSuper Hello NamedSuper!
à la console -
test4.callPrint()
logeraNamedSuper 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é.