• 发生时间:2022-06-16
  • 问题描述:
    • 开发产线工具时,在类 SerialPortClient 中定义了一个 static method _parseData
    • 在这个类的另一个函数中通过 this 来调用 _parseData 时报错:TypeError: this._parseData is not a function
  • 问题类别:软件开发
  • 原因分析:查阅MDN Web docs 关于 static 的文档,发现 js 语法规定 js 类内部的普通函数不能通过 this 来直接调用 static method。
  • 解决方案:文档中给出了两种解决方案:可以通过 SerialPortClient._parseDatathis.constructor._parseData 的方式来调用。
  • 实施结果:采用第一种解决方案后,可以正常调用函数。
  • 经验总结:js 类内部普通函数需要通过CLASSNAME.STATIC_METHOD_NAME()的方式来调用 js static method。

一个能够复现此问题的 demo 代码

class Foo {
  constructor() {
    this._count = 0
  }

  static hi() {
    console.log('hello world')
  }

  display() {
    this.hi()
    console.log('count:', this._count)
  }
}

let foo = new Foo();
foo.display();

在终端使用 node 运行以上脚本,会报以下错误:

$ node static_demo.js
C:\Users\minieye\src\demo\js-static\static_demo.js:11
    this.hi()
         ^

TypeError: this.hi is not a function
    at Foo.display (C:\Users\minieye\src\demo\js-static\static_demo.js:11:10)
    at Object.<anonymous> (C:\Users\minieye\src\demo\js-static\static_demo.js:17:5)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
    at internal/main/run_main_module.js:17:47

关于 js static 的一些补充说明

MDN 文档中介绍了 js 类内部的非 static 方法调用 static 成员时的两种方法:

Static members are not directly accessible using the this keyword from non-static methods. You need to call them using the class name: CLASSNAME.STATIC_METHOD_NAME() / CLASSNAME.STATIC_PROPERTY_NAME or by calling the method as a property of the constructor: this.constructor.STATIC_METHOD_NAME() / this.constructor.STATIC_PROPERTY_NAME

值得注意的是,js 类内部的 static 方法是可以通过 this 来直接调用其他 static 成员的:

In order to call a static method or property within another static method of the same class, you can use the this keyword.

js static method vs Python @staticmethod

我们不妨对比一下 js static method 与 Python staticmethod 的差异。

根据 Python 官方文档关于 @staticmethod 的描述,Python 与 js 的 static method 是类似的,但也有一个差异:

  • js 的 static method 只能通过类名字来调用,不能通过类实例来调用; 而 Python 的 static method 可以通过类名字或类实例来调用。
  • js 类内部的非 statis method 不能通过 this 来直接调用 static method; 而 Python 类内部的非 static method 可以通过 self 来直接调用 static method。

顺便提一下,Python 还有一个 class method,它的调用方式与 static method 类似,但两者是存在明显区别的

  • A class method takes cls as the first parameter while a static method needs no specific parameters.
  • A class method can access or modify the class state while a static method can’t access or modify it.
  • In general, static methods know nothing about the class state.

stack overflow 的这个回答 更深入探讨了 Python classmethod 与 static method 的差异,值得阅读。