乐趣区

关于javascript:精读class-static-block

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 许可证)

退出移动版