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

时间:2021-12-30 04:03:27

What's the standard way to call static methods? I can think of using constructor or 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?

调用静态方法的标准方法是什么?我可以考虑使用构造函数或使用类本身的名称,我不喜欢后者,因为它没有必要。前一种方法是推荐的,还是有别的方法?

Here's a (contrived) example:

这里有一个例子(做作):

class SomeObject {  constructor(n){    this.n = n;  }  static print(n){    console.log(n);  }  printN(){    this.constructor.print(this.n);  }}

3 个解决方案

#1


137  

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(); // Supernew Sub().lognameB(); // Sub

Referring to the static property via the class will be actually static and constantly give the same value. Using this.constructor instead will use dynamic dispatch and refer to the class of the current instance, where the static property might have the inherited value but could also be overridden.

通过类引用静态属性实际上是静态的,并且始终给出相同的值。使用这个。构造函数将使用动态分派并引用当前实例的类,其中静态属性可能具有继承的值,但也可能被重写。

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的行为相匹配,您可以选择通过类名或实例本身引用静态属性。

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中,请使用显式引用。

#2


32  

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可能派生自其他类(es),可能派生了更多的类。

Then accessing

然后访问

  • from static method/getter of Foo
    • some probably overridden static method/getter:
      • this.method()
      • this.method()
      • this.property
      • this.property
    • 有些可能重写了静态方法/getter: this.method() this.property
    • some probably overridden instance method/getter:
      • impossible by design
      • 不可能通过设计
    • 有些可能重写了实例方法/getter:设计上是不可能的
    • own non-overridden static method/getter:
      • Foo.method()
      • Foo.method()
      • Foo.property
      • Foo.property
    • 拥有非重写的静态方法/getter: Foo.method() foo .属性
    • own non-overridden instance method/getter:
      • impossible by design
      • 不可能通过设计
    • 自己的非重写实例方法/getter:设计上是不可能的
  • 从Foo的静态方法/getter中有些可能覆盖了静态方法/getter: this.method()这个。属性一些可能被重写的实例方法/getter:通过设计自己的非重写的静态方法/getter: Foo.method() Foo。属性拥有未重写的实例方法/getter:设计上是不可能的
  • from instance method/getter of Foo
    • some probably overridden static method/getter:
      • this.constructor.method()
      • this.constructor.method()
      • this.constructor.property
      • this.constructor.property
    • 有些可能覆盖了静态方法/getter: this.constructor.method() this.constructor.property。
    • some probably overridden instance method/getter:
      • this.method()
      • this.method()
      • this.property
      • this.property
    • 有些可能重写了实例方法/getter: this.method() this.property
    • own non-overridden static method/getter:
      • Foo.method()
      • Foo.method()
      • Foo.property
      • Foo.property
    • 拥有非重写的静态方法/getter: Foo.method() foo .属性
    • own non-overridden instance method/getter:
      • not possible by intention unless using some workaround:
        • Foo.prototype.method.call( this )
        • Foo.prototype.method。调用(这)
        • Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);
        • 对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);
      • 除非使用一些变通方法:Foo.prototype.method,否则不可能实现。调用(这)对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);
    • 拥有非重写的实例方法/getter:除非使用一些变通方法:Foo.prototype.method。调用(这)对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);
  • 从Foo的实例方法/getter中,有些可能重写了静态方法/getter: this.constructor.method() this.构造函数。属性有些可能覆盖了实例方法/getter: this.method() this。属性拥有非重写的静态方法/getter: Foo.method() Foo。属性拥有非重写的实例方法/getter:除非使用一些变通方法:Foo.prototype.method。调用(这)对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);

Keep in mind that using this isn't working this way when using arrow functions or invoking methods/getters explicitly bound to custom value.

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

Background

  • When in context of an instance's method or getter
    • this is referring to current instance.
    • 这是指当前实例。
    • super is 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).
    • super基本上是指相同的实例,但是在某些类current one的上下文环境中编写的一些寻址方法和getter方法正在扩展(通过使用Foo原型的原型)。
    • definition of instance's class used on creating it is available per this.constructor.
    • 用于创建实例的类的定义可以通过this.构造函数获得。
  • 在实例的方法或getter的上下文中,这是指当前实例。super基本上指的是同一个实例,但是有些寻址方法和getters是在当前类的上下文中编写的(通过使用Foo的原型)。用于创建实例的类的定义可以通过this.构造函数获得。
  • When in context of a static method or 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 and getters written in context of some class current one is extending.
    • super也不是指某个实例,而是指在当前正在扩展的某个类的上下文中编写的静态方法和getter。
  • 当在静态方法或getter的上下文中,无意中没有“当前实例”,因此可以直接引用当前类的定义。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 );

#3


12  

If you are planning on doing any kind of inheritance, then I would recommend this.constructor. This simple example should illustrate why:

如果您打算进行任何类型的继承,那么我将推荐这个。构造函数。这个简单的例子应该说明为什么:

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 log ConstructorSuper Hello ConstructorSuper! to the console
  • test1.callPrint()将记录构造函数超级Hello构造函数!到控制台
  • test2.callPrint() will log ConstructorSub Hello ConstructorSub! to the console
  • callprint()将记录构造子Hello构造子!到控制台

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 log NamedSuper Hello NamedSuper! to the console
  • test3.callPrint()将日志命名为super Hello NamedSuper!到控制台
  • test4.callPrint() will log NamedSuper Hello NamedSub! to the console
  • test4.callPrint()将日志命名为super Hello NamedSub!到控制台

See all the above running in Babel REPL.

请查看在Babel REPL中运行的所有上述内容。

You can see from this that test4 still 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仍然认为它在超类中;在本例中,这似乎不是什么大问题,但如果您试图引用已被重写的成员函数或新成员变量,您将发现自己遇到了麻烦。

#1


137  

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(); // Supernew Sub().lognameB(); // Sub

Referring to the static property via the class will be actually static and constantly give the same value. Using this.constructor instead will use dynamic dispatch and refer to the class of the current instance, where the static property might have the inherited value but could also be overridden.

通过类引用静态属性实际上是静态的,并且始终给出相同的值。使用这个。构造函数将使用动态分派并引用当前实例的类,其中静态属性可能具有继承的值,但也可能被重写。

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的行为相匹配,您可以选择通过类名或实例本身引用静态属性。

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中,请使用显式引用。

#2


32  

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可能派生自其他类(es),可能派生了更多的类。

Then accessing

然后访问

  • from static method/getter of Foo
    • some probably overridden static method/getter:
      • this.method()
      • this.method()
      • this.property
      • this.property
    • 有些可能重写了静态方法/getter: this.method() this.property
    • some probably overridden instance method/getter:
      • impossible by design
      • 不可能通过设计
    • 有些可能重写了实例方法/getter:设计上是不可能的
    • own non-overridden static method/getter:
      • Foo.method()
      • Foo.method()
      • Foo.property
      • Foo.property
    • 拥有非重写的静态方法/getter: Foo.method() foo .属性
    • own non-overridden instance method/getter:
      • impossible by design
      • 不可能通过设计
    • 自己的非重写实例方法/getter:设计上是不可能的
  • 从Foo的静态方法/getter中有些可能覆盖了静态方法/getter: this.method()这个。属性一些可能被重写的实例方法/getter:通过设计自己的非重写的静态方法/getter: Foo.method() Foo。属性拥有未重写的实例方法/getter:设计上是不可能的
  • from instance method/getter of Foo
    • some probably overridden static method/getter:
      • this.constructor.method()
      • this.constructor.method()
      • this.constructor.property
      • this.constructor.property
    • 有些可能覆盖了静态方法/getter: this.constructor.method() this.constructor.property。
    • some probably overridden instance method/getter:
      • this.method()
      • this.method()
      • this.property
      • this.property
    • 有些可能重写了实例方法/getter: this.method() this.property
    • own non-overridden static method/getter:
      • Foo.method()
      • Foo.method()
      • Foo.property
      • Foo.property
    • 拥有非重写的静态方法/getter: Foo.method() foo .属性
    • own non-overridden instance method/getter:
      • not possible by intention unless using some workaround:
        • Foo.prototype.method.call( this )
        • Foo.prototype.method。调用(这)
        • Object.getOwnPropertyDescriptor( Foo.prototype,"property" ).get.call(this);
        • 对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);
      • 除非使用一些变通方法:Foo.prototype.method,否则不可能实现。调用(这)对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);
    • 拥有非重写的实例方法/getter:除非使用一些变通方法:Foo.prototype.method。调用(这)对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);
  • 从Foo的实例方法/getter中,有些可能重写了静态方法/getter: this.constructor.method() this.构造函数。属性有些可能覆盖了实例方法/getter: this.method() this。属性拥有非重写的静态方法/getter: Foo.method() Foo。属性拥有非重写的实例方法/getter:除非使用一些变通方法:Foo.prototype.method。调用(这)对象。getOwnPropertyDescriptor(Foo。原型,“财产”).get.call(这个);

Keep in mind that using this isn't working this way when using arrow functions or invoking methods/getters explicitly bound to custom value.

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

Background

  • When in context of an instance's method or getter
    • this is referring to current instance.
    • 这是指当前实例。
    • super is 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).
    • super基本上是指相同的实例,但是在某些类current one的上下文环境中编写的一些寻址方法和getter方法正在扩展(通过使用Foo原型的原型)。
    • definition of instance's class used on creating it is available per this.constructor.
    • 用于创建实例的类的定义可以通过this.构造函数获得。
  • 在实例的方法或getter的上下文中,这是指当前实例。super基本上指的是同一个实例,但是有些寻址方法和getters是在当前类的上下文中编写的(通过使用Foo的原型)。用于创建实例的类的定义可以通过this.构造函数获得。
  • When in context of a static method or 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 and getters written in context of some class current one is extending.
    • super也不是指某个实例,而是指在当前正在扩展的某个类的上下文中编写的静态方法和getter。
  • 当在静态方法或getter的上下文中,无意中没有“当前实例”,因此可以直接引用当前类的定义。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 );

#3


12  

If you are planning on doing any kind of inheritance, then I would recommend this.constructor. This simple example should illustrate why:

如果您打算进行任何类型的继承,那么我将推荐这个。构造函数。这个简单的例子应该说明为什么:

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 log ConstructorSuper Hello ConstructorSuper! to the console
  • test1.callPrint()将记录构造函数超级Hello构造函数!到控制台
  • test2.callPrint() will log ConstructorSub Hello ConstructorSub! to the console
  • callprint()将记录构造子Hello构造子!到控制台

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 log NamedSuper Hello NamedSuper! to the console
  • test3.callPrint()将日志命名为super Hello NamedSuper!到控制台
  • test4.callPrint() will log NamedSuper Hello NamedSub! to the console
  • test4.callPrint()将日志命名为super Hello NamedSub!到控制台

See all the above running in Babel REPL.

请查看在Babel REPL中运行的所有上述内容。

You can see from this that test4 still 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仍然认为它在超类中;在本例中,这似乎不是什么大问题,但如果您试图引用已被重写的成员函数或新成员变量,您将发现自己遇到了麻烦。