类静态初始化块即将纳入ES2022,我们先一睹为快

开发 前端
对于类的静态部分的设置,我们只有静态字段。ECMAScript建议为类引入静态初始化块,大致上,它对静态类的作用就像构造函数对实例的作用。

[[436293]]

Ron Buckton 提出的 ECMAScript 提案 "类静态初始化块"已进入第四阶段,计划纳入ECMAScript 2022。

为了建立一个类的实例,在JavaScript中有两个结构:

字段:创建(可选择初始化)实例属性。

构造函数:在 setup 完成之前执行的代码块。

对于类的静态部分的设置,我们只有静态字段。ECMAScript建议为类引入静态初始化块,大致上,它对静态类的作用就像构造函数对实例的作用。

[[436294]]

1.为什么我们需要类中的静态块?

在设置静态字段时,使用外部函数通常也可以很好地工作:

  1. class Translator { 
  2.   static translations = { 
  3.     yes: 'ja'
  4.     no'nein'
  5.     maybe: 'vielleicht'
  6.   }; 
  7.   static englishWords = extractEnglish(this.translations); 
  8.   static germanWords = extractGerman(this.translations); 
  9. function extractEnglish(translations) { 
  10.   return Object.keys(translations); 
  11. function extractGerman(translations) { 
  12.   return Object.values(translations); 

使用外部函数 extractEnglish()和 extractGerman() 在这种情况下效果很好,因为我们可以看到它们是从类内部调用的,而且它们完全独立于类。

如果我们想同时设置两个静态字段,事情就变得不那么优雅。

  1. class Translator { 
  2.   static translations = { 
  3.     yes: 'ja'
  4.     no'nein'
  5.     maybe: 'vielleicht'
  6.   }; 
  7.   static englishWords = []; 
  8.   static germanWords = []; 
  9.   static _ = initializeTranslator( // (A) 
  10.     this.translations, this.englishWords, this.germanWords); 
  11. function initializeTranslator(translations, englishWords, germanWords) { 
  12.   for (const [english, german] of Object.entries(translations)) { 
  13.     englishWords.push(english); 
  14.     germanWords.push(german); 
  15.   } 

这一次,有几个问题。

  • 调用initializeTranslator()是一个额外的步骤,要么在创建类之后,在类之外执行。或者通过一个变通方法来执行(A行)。
  • initializeTranslator() 不能访问 Translator 的私有数据。

通过提出的静态块(A行),我们有更优雅的解决方案。

  1. class Translator { 
  2.   static translations = { 
  3.     yes: 'ja'
  4.     no'nein'
  5.     maybe: 'vielleicht'
  6.   }; 
  7.   static englishWords = []; 
  8.   static germanWords = []; 
  9.   static { // (A) 
  10.     for (const [english, german] of Object.entries(this.translations)) { 
  11.       this.englishWords.push(english); 
  12.       this.germanWords.push(german); 
  13.     } 
  14.   } 

2.一个更复杂的例子

在JavaScript中实现枚举的一种方法是通过带有辅助功能的超类Enum

  1. class Enum { 
  2.   static collectStaticFields() { 
  3.     // Static methods are not enumerable and thus ignored 
  4.     this.enumKeys = Object.keys(this); 
  5.   } 
  6. class ColorEnum extends Enum { 
  7.   static red = Symbol('red'); 
  8.   static green = Symbol('green'); 
  9.   static blue = Symbol('blue'); 
  10.   static _ = this.collectStaticFields(); // (A) 
  11.  
  12.   static logColors() { 
  13.     for (const enumKey of this.enumKeys) { // (B) 
  14.       console.log(enumKey); 
  15.     } 
  16.   } 
  17. ColorEnum.logColors(); 
  18.  
  19. // Output
  20. // 'red' 
  21. // 'green' 
  22. // 'blue' 

我们需要收集静态字段,以便我们可以遍历枚举项的键(B行)。这是在创建所有静态字段之后的最后一步。我们再次使用一个变通方法(A行),静态块会更优雅。

3.详情

静态块的具体内容相对来说是合乎逻辑的(相比之下,实例成员的规则更为复杂):

  • 每个类可以有一个以上的静态块。
  • 静态块的执行是与静态字段初始化器的执行交错进行的。
  • 超类的静态成员在子类的静态成员之前被执行。

下面的代码展示了这些规则:

  1. class SuperClass { 
  2.   static superField1 = console.log('superField1'); 
  3.   static { 
  4.     assert.equal(this, SuperClass); 
  5.     console.log('static block 1 SuperClass'); 
  6.   } 
  7.   static superField2 = console.log('superField2'); 
  8.   static { 
  9.     console.log('static block 2 SuperClass'); 
  10.   } 
  11.  
  12. class SubClass extends SuperClass { 
  13.   static subField1 = console.log('subField1'); 
  14.   static { 
  15.     assert.equal(this, SubClass); 
  16.     console.log('static block 1 SubClass'); 
  17.   } 
  18.   static subField2 = console.log('subField2'); 
  19.   static { 
  20.     console.log('static block 2 SubClass'); 
  21.   } 
  22.  
  23. // Output
  24. // 'superField1' 
  25. // 'static block 1 SuperClass' 
  26. // 'superField2' 
  27. // 'static block 2 SuperClass' 
  28. // 'subField1' 
  29. // 'static block 1 SubClass' 
  30. // 'subField2' 
  31. // 'static block 2 SubClass' 

4.在引擎中支持类静态块

  • V8: unflagged in v9.4.146 (source)
  • SpiderMonkey: behind a flag in v92, intent to ship unflagged in v93 (source)
  • TypeScript: v4.4 (source)

5.JS 是否变得太像Java和/或一塌糊涂?

这是一个很小的功能,不会与其他功能竞争。我们已经可以通过 static _ = ... 的字段来运行静态代码。静态块意味着这种变通方法不再需要了。

除此之外,类只是JavaScript程序员腰带上的众多工具之一。我们中的一些人使用它,另一些人不使用它,而且有许多替代方案。即使是使用类的 JS 代码,也经常使用函数,而且往往是轻量级的。

[[436295]]

6.总结

类静态块是一个相对简单的功能,它完善了类的静态功能。粗略来说,它是实例构造函数的静态版本。它主要在我们需要设置一个以上的静态字段时有用。

作者:Dr. Axel Rauschmayer 译者:前端小智

来源:2ality 原文:https://2ality.com/2021/09/class-static-block.html

 

责任编辑:姜华 来源: 大迁世界
相关推荐

2016-12-01 07:53:36

AWSAWS re:InveAWS新产品

2010-02-03 11:01:18

C++类静态成员初始化

2024-08-26 15:06:20

2022-08-05 13:14:25

ES2022JavaScript代码

2009-08-31 09:47:22

C#静态变量初始化

2012-05-23 12:46:53

JavaJava类

2010-08-06 13:51:12

OracleFusionApp

2019-02-20 15:42:28

机器学习人工智能计算机

2012-02-28 10:04:09

Java

2024-03-08 08:26:25

类的加载Class文件Java

2023-11-12 23:08:17

C++初始化

2012-04-09 13:43:12

Java

2022-03-23 09:55:14

PythonGUI代码

2013-03-04 11:10:03

JavaJVM

2024-03-28 12:32:18

JVM类加载构造器

2009-08-28 11:24:48

C#一维数组初始化

2011-06-17 15:29:44

C#对象初始化器集合初始化器

2024-03-12 07:44:53

JVM双亲委托机制类加载器
点赞
收藏

51CTO技术栈公众号