为何 JavaScript 的私有属性使用 # 符号

这几天 JavaScript 的私有属性又成为了前端社区热议的话题。缘由很简单,这家伙长这样:前端

惊不惊喜!意不意外!git

并且 TC39 委员会以及对此达成了一致意见,而且该提案已经进入了 stage 3。在 es 规范阶段 stage 3 是候选提案,又很大的可能会进入到下一个标准。到目前为止,已经能够肯定会进入 es2019(es10) 标准的有 optional-catch-binding 和 proposal-json-superset。而这个 private 大概也只能进入到 es2020 后的标准了。github

TC39 委员会解释道,他们也是作了深思熟虑最终选择了 # 符号,而没有使用 private 关键字。其中还讨论了把 private# 符号一块儿使用的方案。而且还打算预留了一个 @ 关键字做为 protected 属性😄,不过这个 @ 已经被 decorator 使用了。npm

咱们在此就不讨论这个语法到底丑不丑了,这不显而易见的吗,还用讨论吗。咱们讨论一下为何要使用 # 符号。json

有人说,“若是这个进入了规范,我就不再用 JavaScript了,之后项目都用 TypeScript 写”。函数

这就有点由不得你了,咱们看 TypeScript 的官网介绍:this

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.spa

TypeScript 是 JavaScript 的超集,言外之意就是 js 有的 ts 也全都有。对于一个已经进入 stage 3 的提案,ts 固然不会坐视不理的。ts 也正在抓紧支持这个语法:All Bloomberg Changes for Private Fields and Methodscode

也有人疑问:“为何 ts 的私有属性就可使用 private 关键字,而 js 就不行呢?”cdn

由于 ts 的 private 和这个 # 语法彻底是不一样的东西。TypeScript 是一种静态类型语言而不是强类型语言(有争议)。private 只是在编译时作检查,最终生成的 js 代码中被 private 修饰的属性依然是公开的。

那为何不使用下划线(_)呢,毕竟这个已是私有属性的非正式的最佳实践了?

之因此不选择下划线是出于兼容性考虑,另外一个因为兼容性而妥协的提案是 JavaScript 社区由一个库引起的“smoosh门”事件到底怎么回事? 因为下划线是合法的 js 变量标识符因此不少的代码都使用了下划线,若是新的 js 规范把下划线开头的变量做为私有属性,那么会致使不少就代码没法运行。好比知名的 lodash 和 underscore 库就是使用的下划线,这两个库每周在 npm 的下载量是 2 千万。

“为何不使用 private?”

这里有一个经典的例子:

class Foo {
  private value;

  equals(foo) {
    return this.value === foo.value;
  }
}
复制代码

在不少面向对象语言中都有这种写法,判断类的两个实例是否相等。若是在 js 中也这么写,会有一些问题。

在静态类型语言中,咱们能够明确的知道传入的参数是 Foo 类型,所以在 Fooequals 方法中咱们能够访问 foo 的私有属性 value。可是 js 是动态类型的,咱们没法知道参数 foo 的类型,若是咱们传入了 {value: '123'} 会,则函数的行为不符合咱们的预期。这也致使了该函数有时访问的是私有属性,有时访问的是公有属性。

另外一方面,私有属性只在类的内部能够访问,外部没法访问,甚至不知道此变量的存在。所以在 JavaScript 中同名的私有属性和公有属性能够同时存在,二者使用 # 作区分。

若是使用 private 进行修饰,则咱们能够探测类的私有属性:

foo.bar = 1; // Error: `bar` is private! (boom... detected)
复制代码

或者:

foo.bar = 1;
foo.bar; // `undefined` (boom... detected again)
复制代码

PS:虽然社区的总体意见是使用 private 代替 #,可是 TC39 的意见很坚定。

最后,这种引入私有属性的方式,其实隐式的为 js 引入了静态类型。

相关文章
相关标签/搜索