class-static-block 提案于 2021.9.1 进入 stage4,是一个基于 Class 加强的提案。

本周咱们联合 ES2022 feature: class static initialization blocks 这篇文章一起讨论一下这个个性。

概述

为什么咱们须要 class static block 这个语法呢?其中一个起因是对 Class 动态变量的灵便赋值需要。以上面为例,咱们想在 Class 外部对动态变量做批量初始化,就不得不写一个无用的 _ 变量用来做初始化的逻辑:

class Translator {  static translations = {    yes: 'ja',    no: 'nein',    maybe: 'vielleicht',  };  static englishWords = [];  static germanWords = [];  static _ = initializeTranslator( // (A)    this.translations, this.englishWords, this.germanWords);}function initializeTranslator(translations, englishWords, germanWords) {  for (const [english, german] of Object.entries(translations)) {    englishWords.push(english);    germanWords.push(german);  }}

而且咱们为什么把 initializeTranslator 写在里面呢?就因为在 Class 外部不能写代码块,但这造成一个重大的问题,是内部函数无法访问 Class 外部属性,所以须要做一堆干燥的传值。

从这个例子看出,咱们为了自定义一段动态变量初始化逻辑,须要做出两个斗争:

  1. 在内部定义一个函数,并承受大量 Class 成员变量传参。
  2. 在 Class 外部定义一个无意义的变量 _ 用来启动这个函数逻辑。

这切实太没有代码谋求了,咱们在 Class 外部做掉这些逻辑不就简洁了吗?这就是 class static block 个性:

class Translator {  static translations = {    yes: 'ja',    no: 'nein',    maybe: 'vielleicht',  };  static englishWords = [];  static germanWords = [];  static { // (A)    for (const [english, german] of Object.entries(this.translations)) {      this.englishWords.push(english);      this.germanWords.push(german);    }  }}

能够看到,static 关键字前面不跟变量,而是间接跟一个代码块,就是 class static block 语法的特色,在这个代码块外部,能够通过 this 拜访 Class 所有成员变量,包含 # 公有变量。

原文对这个个性应用介绍就完结了,最初还提到一个细节,就是执行程序。即所有 static 变量或区块都按程序执行,父类优先执行:

class SuperClass {  static superField1 = console.log('superField1');  static {    assert.equal(this, SuperClass);    console.log('static block 1 SuperClass');  }  static superField2 = console.log('superField2');  static {    console.log('static block 2 SuperClass');  }}class SubClass extends SuperClass {  static subField1 = console.log('subField1');  static {    assert.equal(this, SubClass);    console.log('static block 1 SubClass');  }  static subField2 = console.log('subField2');  static {    console.log('static block 2 SubClass');  }}// Output:// 'superField1'// 'static block 1 SuperClass'// 'superField2'// 'static block 2 SuperClass'// 'subField1'// 'static block 1 SubClass'// 'subField2'// 'static block 2 SubClass'

所以 Class 内容许有多个 class static block,父类和子类也能够有,不同执行程序后果必定不同,这个选择权交给了使用者,因为执行程序和书写程序统一。

精读

联合提案来看,class static block 还有一个动机,就是给了一个拜访公有变量的机制:

let getX;export class C {  #x  constructor(x) {    this.#x = { data: x };  }  static {    // getX has privileged access to #x    getX = (obj) => obj.#x;  }}export function readXData(obj) {  return getX(obj).data;}

实践上内部无论如何都无法访问 Class 公有变量,但下面例子的 readXData 就能够,而且不会运行时报错,起因就是其整个流程都是非法的,最重要的起因是,class static block 能够同时拜访公有变量与全局变量,所以能够利用其做一个 “内外夹攻”。

不过我并不感觉这是一个好点子,反而像一个 "BUG",因为任何对规定的冲破都会为可维护性埋下隐患,除非这个个性用在稳固的工具、框架层,用来做一些便利性工作,最终晋升了利用编码的体验,这种用法是能够承受的。

最初要意识到,class static block 实质上并没有减少新性能,咱们齐全能够用一般动态变量代替,只是写起来很不天然,所以这个个性能够了解为对缺点的补充,或者是语法欠缺。

总结

总的来说,class static block 在 Class 内创立了一个块状作用域,这个作用域内领有拜访 Class 外部公有变量的特权,且这个块状作用域仅在引擎调用时初始化执行一次,是一个比拟不便的语法。

原文下方有一些拥护声音,说这是对 JS 的复杂化,也有诸如 JS 越来越像 Java 的声音,不过我更同意作者的观点,也就是 Js 中 Class 并不是全副,当初越来越多代码应用函数式语法,即使应用了 Class 的场景也会存在大量函数申明,所以 class static block 这个提案对开发者的感知实际上并不大。

探讨地址是:精读《class static block》· Issue #351 · dt-fe/weekly

如果你想参加探讨,请 点击这里,每周都有新的主题,周末或周一公布。前端精读 - 帮你筛选靠谱的内容。

关注 前端精读微信公众号

<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg">

版权申明:自在转载-非商用-非衍生-放弃署名(创意共享 3.0 许可证)