调用静态方法的标准方式是什么?我可以考虑使用构造函数或使用类本身的名称,我不喜欢后者,因为它感觉没有必要。前者是推荐的方法,还是有其他方法?
这里有一个(虚构的)例子:
class SomeObject {
constructor(n){
this.n = n;
}
static print(n){
console.log(n);
}
printN(){
this.constructor.print(this.n);
}
}
调用静态方法的标准方式是什么?我可以考虑使用构造函数或使用类本身的名称,我不喜欢后者,因为它感觉没有必要。前者是推荐的方法,还是有其他方法?
这里有一个(虚构的)例子:
class SomeObject {
constructor(n){
this.n = n;
}
static print(n){
console.log(n);
}
printN(){
this.constructor.print(this.n);
}
}
如果您计划进行任何类型的继承,那么我建议使用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()将记录ConstructorSuper Hello ConstructorSuper!到 控制台 test2.callPrint()将记录ConstructorSub Hello ConstructorSub!到控制台
命名类不能很好地处理继承,除非显式地重定义每个引用命名类的函数。这里有一个例子:
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()将记录NamedSuper Hello NamedSuper!到 控制台 test4.callPrint()将记录NamedSuper Hello NamedSub!到控制台
看到所有以上运行在Babel REPL。
你可以看到test4仍然认为它在超类中;在本例中,这似乎不是什么大问题,但如果您试图引用已覆盖的成员函数或新成员变量,那么您将遇到麻烦。
这两种方法都是可行的,但是当涉及到带有重写静态方法的继承时,它们所做的事情是不同的。选择一个你期待其行为的人:
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
通过类引用静态属性实际上是静态的,并不断给出相同的值。使用这个。构造函数将使用动态分派并引用当前实例的类,其中静态属性可能具有继承的值,但也可能被重写。
这与Python的行为相匹配,在Python中,您可以选择通过类名或实例本身引用静态属性。
如果您希望静态属性不被覆盖(并且总是引用当前类中的一个),就像在Java中一样,使用显式引用。
我无意中在这个帖子中寻找类似情况的答案。基本上所有的答案都找到了,但仍然很难从中提取出要点。
访问类型
假设一个类Foo可能从其他类派生而来,这些类可能派生出更多的类。
然后访问:
from static method/getter of Foo class: some probably overridden static method/getter: this.method() this.property some probably overridden instance method/getter: impossible by design own non-overridden static method/getter: Foo.method() Foo.property own non-overridden instance method/getter: impossible by design from instance method/getter of Foo class: some probably overridden static method/getter: this.constructor.method() this.constructor.property some probably overridden instance method/getter: this.method() this.property own non-overridden static method/getter: Foo.method() Foo.property own non-overridden instance method/getter: not possible by intention unless using some workaround: Foo.prototype.method.call( this ) Object.getOwnPropertyDescriptor(Foo.prototype,'<property>' ).get.call(this)
请记住,当使用箭头函数或调用显式绑定到自定义值的方法/getter时,使用此方法不能以这种方式工作。
背景
When in context of an instance's method/getter this is referring to current instance. super is basically referring to same instance, but somewhat addressing methods/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/getter there is no "current instance" by intention and so: this is available to refer to the definition of current class directly. super is not referring to some instance either, but to static methods/getters written in context of some class current one is extending.
结论
试试下面的代码:
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 );