详解JavaScript 新语法之Class 的私有属性与私有方法
译者按:为什么偏要用#符号?
原文:JavaScript'snew#privateclassfields
•译者:Fundebug
本文采用意译,版权归原作者所有
proposal-class-fields与proposal-private-methods定义了Class的私有属性以及私有方法,这2个提案已经处于Stage3,这就意味着它们已经基本确定下来了,等待被加入到新的ECMAScript版本中。事实上,最新的Chrome已经支持了Class私有属性。
那么,对于Class的私有属性与私有方法,它们究竟是什么呢?它们是怎样工作的?为什么要使用#符号来定义呢?
Class的私有属性语法如下:
classPoint{
#x;
#y;
constructor(x,y){
this.#x=x;
this.#y=y;
}
equals(point){
returnthis.#x===point.#x&&this.#y===point.#y;
}
}
我们可以将其语法理解为2个部分:
•定义Class私有属性
•引用Class私有属性
定义Class私有属性
私有属性与公共属性的定义方式几乎是一样的,只是需要在属性名称前面添加#符号:
classFoo{
publicFieldName=1;
#privateFieldName=2;
}
定义私有属性的时候也可以不用赋值:
classFoo{
#privateFieldName;
}
引用Class私有属性
引用私有属性也只需要使用#就好了。
classFoo{
publicFieldName=1;
#privateFieldName=2;
add(){
returnthis.publicFieldName+this.#privateFieldName;
}
}
其中,this.#可以简化,去掉this也没问题,下面两种写法是等价的:
method(){
#privateFieldName;
}
method(){
this.#privateFieldName;
}
在Class定义中引用Class实例的私有属性
对于私有属性,我们是不可以直接通过Class实例来引用的,这也是私有属性的本来含义。但是有一种情况除外,在Class定义中,我们可以引用Class实例的私有属性:
classFoo{
#privateValue=42;
staticgetPrivateValue(foo){
returnfoo.#privateValue;
}
}
Foo.getPrivateValue(newFoo());//>>42
其中,foo是Foo的实例,在Class定义中,我们可以通过foo来引用私有属性#privateValue。
Class的私有方法
Class的私有属性是提案proposal-class-fields的一部分,这个提案只关注Class的属性,它并没有对Class的方法进行任何修改。而Class的私有方法是提案proposal-class-fields的一部分。
Class的私有方法语法如下:
classFoo{
constructor(){
this.#method();
}
#method(){
//...
}
}
我们也可以将函数赋值给私有属性:
classFoo{
constructor(){
this.#method();
}
#method=()=>{
//...
};
}
封装(隐藏)私有属性
我们不能直接通过Class实例引用私有属性,我们只能在Class定义中引用它们:
classFoo{
#bar;
method(){
this.#bar;//Works
}
}
letfoo=newFoo();
foo.#bar;//Invalid!
另外,要做到真正的私有的话,我们应该无法检测这个私有属性是否存在,因此,我们需要允许定义同名的公共属性:
classFoo{
bar=1;//publicbar
#bar=2;//privatebar
}
如果我们不允许公共属性与私有属性同名,我们则可以通过给同名的公共属性复制监测该私有属性是否存在:
foo.bar=1;//Error:`bar`isprivate!(报错,说明私有属性存在)
不报错也行:
foo.bar=1; foo.bar;//`undefined`(赋值失败,说明私有属性存在)
对于subclass应该同样如此,它也允许公共属性与私有属性同名:
classFoo{
#fieldName=1;
}
classBarextendsFoo{
fieldName=2;//Works!
}
关于Class私有属性的封装,可以参考Whyisencapsulationagoalofthisproposal?。
为什么使用#符号?
很多人都有一个疑问,为什么JS不能学习其他语言,使用private来定义私有属性和私有方法?为什么要使用奇怪的#符号?
使用private的话,代码要舒服很多:
classFoo{
privatevalue;
equals(foo){
returnthis.value===foo.value;
}
}
为什么不使用private来定义私有属性?
很多语言使用private来定义私用属性,如下:
classEnterpriseFoo{
publicbar;
privatebaz;
method(){
this.bar;
this.baz;
}
}
对于这些语言属性,私用属性和公共属性的引用方式是相同的,因此他们可以使用private来定义私有属性。
但是,对于JavaScript来说,我们不能使用this.field来引用私有属性(我接下来会解释原因),我们需要在语法层面上区分私有属性和公共属性。在定义和引用私有属性的时候,使用#符号,私有属性与公共属性可以很好地区分开来。
为什么引用私有属性的时候需要#符号?
引用私有属性的时候,我们需要this.#field,而不是this.field,原因如下:
•因为我们需要封装私有属性,我们需要允许公共属性与私有属性同名,因此私有属性与公共属性的引用方式必须不一样。这一点我们在前文已经详述。
•公共属性可以通过this.field以及this['field']来引用,但是私有属性不能支持this['field']这种方式,否则会破坏私有属性的隐私性,示例如下:
classDictextendsnull{
#data=something_secret;
add(key,value){
this[key]=value;
}
get(key){
returnthis[key];
}
}
newDict().get("#data");//返回私有属性
因此,私有属性与公共属性的引用方式必须不一样,否则会破坏this['field']语法。
•私有属性与公共属性的引用方式一样的话,会导致我们每次都需要去检查属性是公共的还是私有的,这会造成严重的性能问题。
这篇文章遵循CreativeCommonsAttribution4.0InternationalLicense。
参考
•Whyisencapsulationagoalofthisproposal?
总结
以上所述是小编给大家介绍的JavaScript新语法之Class的私有属性与私有方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!