调用静态方法的标准方法是什么?我可以考虑使用constructor或使用类本身的名称,我不喜欢后者,因为它觉得没有必要。前者是推荐的方式,还是有别的方法?
这是一个(人为的)示例:
class SomeObject {
  constructor(n){
    this.n = n;
  }
  static print(n){
    console.log(n);
  }
  printN(){
    this.constructor.print(this.n);
  }
}
调用静态方法的标准方法是什么?我可以考虑使用constructor或使用类本身的名称,我不喜欢后者,因为它觉得没有必要。前者是推荐的方式,还是有别的方法?
这是一个(人为的)示例:
class SomeObject {
  constructor(n){
    this.n = n;
  }
  static print(n){
    console.log(n);
  }
  printN(){
    this.constructor.print(this.n);
  }
}
这两种方式都是可行的,但是当涉及到使用重写的静态方法进行继承时,它们会做不同的事情。选择您期望的行为:
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
通过类引用静态属性实际上是静态的,并不断给出相同的值。使用this.constructor替代将使用动态调度并引用当前实例的类,其中静态属性可能具有继承的值,但也可能被覆盖。
这与 Python 的行为相匹配,您可以选择通过类名或实例来引用静态属性self。
如果您希望静态属性不被覆盖(并且始终引用当前类之一),就像在 Java 中一样,请使用显式引用。
我偶然发现了这个线程,以寻找类似案例的答案。基本上所有的答案都找到了,但仍然很难从中提取要领。
假设一个类 Foo 可能派生自其他一些类,并且可能有更多的类从它派生而来。
然后访问
this.method()this.propertyFoo.method()Foo.propertythis.constructor.method()this.constructor.propertythis.method()this.propertyFoo.method()Foo.propertyFoo.prototype.method.call( this )Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);请记住,使用
this箭头函数或调用明确绑定到自定义值的方法/getter 时, using不会以这种方式工作。
this 指的是当前实例。super 基本上指的是同一个实例,但有些寻址方法和 getter 是在当前正在扩展的某个类的上下文中编写的(通过使用 Foo 原型的原型)。this.constructor.this 可以直接引用当前类的定义。super 也不是指某个实例,而是指在当前正在扩展的某个类的上下文中编写的静态方法和 getter。试试这个代码:
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 );
如果您打算进行任何类型的继承,那么我会推荐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!到控制台从中可以看出,test4仍然认为它在超类中;在这个例子中,它可能看起来不是什么大问题,但是如果您试图引用已被覆盖的成员函数或新的成员变量,您会发现自己遇到了麻烦。