首页 文章

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

提问于
浏览
140

调用静态方法的标准方法是什么?我可以想到使用 constructor 或者使用类本身的名称,我觉得没必要_733610 . 前者是推荐的方式,还是还有其他的东西?

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

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

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

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

3 回答

  • 172

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

    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 来引用静态属性 .

    如果您希望不覆盖静态属性(并且始终引用当前类的静态属性)like in Java,请使用显式引用 .

  • 50

    我偶然发现了这个线程,寻找类似案例的答案 . 基本上所有的答案都找到了,但是仍然很难从中提取出必需品 .

    各种访问

    假设一个类Foo可能派生自其他一些类,可能有更多来自它的类 .

    然后访问

    • from static Foo的方法/获取者

    • 有些可能 overridden static 方法/ getter:

    • this.method()

    • this.property

    • 有些可能 overridden instance 方法/ getter:

    • 设计不可能

    • 拥有 non-overridden static 方法/ getter:

    • Foo.method()

    • Foo.property

    • 拥有 non-overridden instance 方法/ getter:

    • 设计不可能

    • from instance Foo的方法/ getter

    • 有些可能 overridden static 方法/ getter:

    • this.constructor.method()

    • this.constructor.property

    • 有些可能 overridden instance 方法/ getter:

    • this.method()

    • this.property

    • 拥有 non-overridden static 方法/ getter:

    • Foo.method()

    • Foo.property

    • 拥有 non-overridden instance 方法/ getter:
      除非使用某些解决方法,否则

    • 无意

    • Foo.prototype.method.call( this )

    • Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);

    请记住,使用箭头函数或调用显式绑定到自定义值的方法/ getter时,使用此方法不起作用 .

    背景

    • 在实例的方法或getter的上下文中

    • this 指的是当前实例 .

    • super 基本上是指同一个实例,但有些寻址方法和getter是在某个类当前类的上下文中编写的(通过使用Foo原型的原型) .

    • 用于创建实例的类的定义可按 this.constructor 获得 .

    • 在静态方法或getter的上下文中,没有"current instance"意图等等

    • 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 );
    
  • 14

    如果您计划进行任何类型的继承,那么我建议 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! 记录到控制台

    See all the above running in Babel REPL .

    你可以从中看到 test4 仍然认为它会发现自己陷入困境 .

相关问题