这几天 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 Methods。code
也有人疑问:“为何 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
类型,所以在 Foo
的 equals
方法中咱们能够访问 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 引入了静态类型。