Javascript 从常规 ES6 类方法调用静态方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28627908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Call static methods from regular ES6 class methods
提问by simonzack
What's the standard way to call static methods? I can think of using constructoror using the name of the class itself, I don't like the latter since it doesn't feel necessary. Is the former the recommended way, or is there something else?
调用静态方法的标准方法是什么?我可以考虑使用constructor或使用类本身的名称,我不喜欢后者,因为它觉得没有必要。前者是推荐的方式,还是有其他方式?
Here's a (contrived) example:
这是一个(人为的)示例:
class SomeObject {
constructor(n){
this.n = n;
}
static print(n){
console.log(n);
}
printN(){
this.constructor.print(this.n);
}
}
回答by Bergi
Both ways are viable, but they do different things when it comes to inheritance with an overridden static method. Choose the one whose behavior you expect:
这两种方式都是可行的,但是当涉及到使用重写的静态方法进行继承时,它们会做不同的事情。选择您期望的行为:
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
Referring to the static property via the class will be actually static and constantly give the same value. Using this.constructorinstead will use dynamic dispatch and refer to the class of the current instance, where the static property mighthave the inherited value but could also be overridden.
通过类引用静态属性实际上是静态的,并不断给出相同的值。使用this.constructor替代将使用动态调度并引用当前实例的类,其中静态属性可能具有继承的值,但也可能被覆盖。
This matches the behavior of Python, where you can choose to refer to static properties either via the class name or the instance self.
这与 Python 的行为相匹配,您可以选择通过类名或实例来引用静态属性self。
If you expect static properties not to be overridden (and always refer to the one of the current class), like in Java, use the explicit reference.
如果您希望静态属性不被覆盖(并且始终引用当前类之一),就像在 Java 中一样,请使用显式引用。
回答by Thomas Urban
I stumbled over this thread searching for answer to similar case. Basically all answers are found, but it's still hard to extract the essentials from them.
我偶然发现了这个线程,寻找类似案例的答案。基本上所有的答案都找到了,但仍然很难从中提取要领。
Kinds of Access
访问类型
Assume a class Foo probably derived from some other class(es) with probably more classes derived from it.
假设一个类 Foo 可能派生自其他一些类,并且可能有更多的类从它派生而来。
Then accessing
然后访问
- from staticmethod/getter of Foo
- some probably overridden staticmethod/getter:
this.method()this.property
- some probably overridden instancemethod/getter:
- impossible by design
- own non-overridden staticmethod/getter:
Foo.method()Foo.property
- own non-overridden instancemethod/getter:
- impossible by design
- some probably overridden staticmethod/getter:
- from instancemethod/getter of Foo
- some probably overridden staticmethod/getter:
this.constructor.method()this.constructor.property
- some probably overridden instancemethod/getter:
this.method()this.property
- own non-overridden staticmethod/getter:
Foo.method()Foo.property
- own non-overridden instancemethod/getter:
- not possible by intention unless using some workaround:
Foo.prototype.method.call( this )Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);
- not possible by intention unless using some workaround:
- some probably overridden staticmethod/getter:
- 来自Foo 的静态方法/getter
- 一些可能被覆盖的静态方法/getter:
this.method()this.property
- 一些可能被覆盖的实例方法/getter:
- 设计不可能
- 自己的非覆盖静态方法/getter:
Foo.method()Foo.property
- 自己的非覆盖实例方法/getter:
- 设计不可能
- 一些可能被覆盖的静态方法/getter:
- 来自Foo 的实例方法/getter
- 一些可能被覆盖的静态方法/getter:
this.constructor.method()this.constructor.property
- 一些可能被覆盖的实例方法/getter:
this.method()this.property
- 自己的非覆盖静态方法/getter:
Foo.method()Foo.property
- 自己的非覆盖实例方法/getter:
- 除非使用一些解决方法,否则不可能有意为之:
Foo.prototype.method.call( this )Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);
- 除非使用一些解决方法,否则不可能有意为之:
- 一些可能被覆盖的静态方法/getter:
Keep in mind that using
thisisn't working this way when using arrow functions or invoking methods/getters explicitly bound to custom value.
请记住,
this当使用箭头函数或调用明确绑定到自定义值的方法/getter 时, using不会以这种方式工作。
Background
背景
- When in context of an instance's method or getter
thisis referring to current instance.superis basically referring to same instance, but somewhat addressing methods and getters written in context of some class current one is extending (by using the prototype of Foo's prototype).- definition of instance's class used on creating it is available per
this.constructor.
- When in context of a static method or getter there is no "current instance" by intention and so
thisis available to refer to the definition of current class directly.superis not referring to some instance either, but to static methods and getters written in context of some class current one is extending.
- 在实例的方法或 getter 的上下文中时
this指的是当前实例。super基本上指的是同一个实例,但有些寻址方法和 getter 是在当前正在扩展的某个类的上下文中编写的(通过使用 Foo 原型的原型)。- 用于创建实例的类的定义在每个
this.constructor.
- 当在静态方法或 getter 的上下文中没有意图的“当前实例”时,因此
this可以直接引用当前类的定义。super也不是指某个实例,而是指在当前正在扩展的某个类的上下文中编写的静态方法和 getter。
Conclusion
结论
Try this 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 );
回答by Andrew Odri
If you are planning on doing any kind of inheritance, then I would recommend this.constructor. This simple example should illustrate why:
如果您打算进行任何类型的继承,那么我会推荐this.constructor. 这个简单的例子应该说明为什么:
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()will logConstructorSuper Hello ConstructorSuper!to the consoletest2.callPrint()will logConstructorSub Hello ConstructorSub!to the console
test1.callPrint()将登录ConstructorSuper Hello ConstructorSuper!到控制台test2.callPrint()将登录ConstructorSub Hello ConstructorSub!到控制台
The named class will not deal with inheritance nicely unless you explicitly redefine every function that makes a reference to the named Class. Here is an example:
命名类不会很好地处理继承,除非您明确重新定义引用命名类的每个函数。下面是一个例子:
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()will logNamedSuper Hello NamedSuper!to the consoletest4.callPrint()will logNamedSuper Hello NamedSub!to the console
test3.callPrint()将登录NamedSuper Hello NamedSuper!到控制台test4.callPrint()将登录NamedSuper Hello NamedSub!到控制台
See all the above running in Babel REPL.
You can see from this that test4still thinks it's in the super class; in this example it might not seem like a huge deal, but if you are trying to reference member functions that have been overridden or new member variables, you'll find yourself in trouble.
从中可以看出,test4仍然认为它在超类中;在这个例子中,它可能看起来不是什么大问题,但是如果您试图引用已被覆盖的成员函数或新的成员变量,您会发现自己遇到了麻烦。

