这几天 JavaScript 的私有属性又成为了前端社区热议的话题。原因很简单,这家伙长这样:
惊不惊喜!意不意外!
而且 TC39 委员会以及对此达成了一致意见,并且该提案已经进入了 stage 3。在 es 规范阶段 stage 3 是候选提案,又很大的可能会进入到下一个标准。到目前为止,已经可以确定会进入 es2019(es10) 标准的有 optional-catch-binding 和 proposal-json-superset。而这个 private 大概也只能进入到 es2020 后的标准了。
TC39 委员会解释道,他们也是做了深思熟虑最终选择了 # 符号,而没有使用 private 关键字。其中还讨论了把 private 和 # 符号一起使用的方案。并且还打算预留了一个 @ 关键字作为 protected 属性😄,不过这个 @ 已经被 decorator 使用了。
我们在此就不讨论这个语法到底丑不丑了,这不显而易见的吗,还用讨论吗。我们讨论一下为什么要使用 # 符号。
有人说,“如果这个进入了规范,我就再也不用 JavaScript了,以后项目都用 TypeScript 写”。
这就有点由不得你了,我们看 TypeScript 的官网介绍:
TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
TypeScript 是 JavaScript 的超集,言外之意就是 js 有的 ts 也全都有。对于一个已经进入 stage 3 的提案,ts 当然不会坐视不理的。ts 也正在抓紧支持这个语法:All Bloomberg Changes for Private Fields and Methods。
也有人疑问:“为什么 ts 的私有属性就可以使用 private 关键字,而 js 就不行呢?”
因为 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 引入了静态类型。
来自公众号:justjavac 地址:https://mp.weixin.qq.com/s/yo6jKu5FC6ekY28Rmuieug