提问者:小点点

从常规ES6类方法调用静态方法


调用静态方法的标准方式是什么?我可以想到使用构造函数或者使用类本身的名称,我不喜欢后者,因为它感觉没有必要。前者是推荐的方式,还是有其他方法?

这是一个(人为的)例子:

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

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

  printN(){
    this.constructor.print(this.n);
  }
}

共3个答案

匿名用户

这两种方式都是可行的,但在使用重写的静态方法进行继承时,它们会做不同的事情。选择您期望其行为的那个:

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.构造函数将使用动态调度并引用当前实例的类,其中静态属性可能具有继承的值,但也可以被覆盖。

这与Python的行为相匹配,您可以选择通过类名或实例self引用静态属性。

如果您希望不重写静态属性(并且始终引用当前类中的一个),如在Java中,请使用显式引用。

匿名用户

我偶然发现了这个线索,寻找类似案例的答案。基本上所有的答案都找到了,但仍然很难从中提取要点。

假设一个类Foo可能派生自其他,其中可能派生了更多的类。

然后访问:

  • from静态Foo类的方法/getter:
    • 一些可能覆盖的静态方法/getter:
      • this. method()
      • this.property
      • 设计上不可能
      • Foo. method()
      • Foo.property
      • 设计上不可能
      • 一些可能覆盖的静态方法/getter:
        • this.构造函数. method()
        • this.constructor.property
        • this. method()
        • this.property
        • Foo. method()
        • Foo.property
        • 除非使用一些解决方法,否则不可能有意:
          • Foo.prototype.method.call(this)
          • 对象。获取自己的属性描述符(Foo。原型,'

          请记住,在使用箭头函数或调用显式绑定到自定义值的方法/getter时,使用this不是这样工作的。

          • 当在实例的方法/getter的上下文中时
            • this指的是当前实例。
            • super基本上指的是同一个实例,但在某些的上下文中编写的一些寻址方法/getter正在扩展(通过使用Foo的原型)。
            • 创建实例时使用的实例的定义可通过this.构造函数获得。
            • 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.构造函数。这个简单的例子应该说明为什么:

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的函数,否则命名类不会很好地处理继承。这是一个例子:

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仍然认为它在超类中;在这个例子中,这可能看起来没什么大不了的,但是如果你试图引用已经被覆盖的成员函数或新的成员变量,你会发现自己遇到了麻烦。