详解JavaScript 新语法之Class 的私有属性与私有方法


Posted in Javascript onApril 23, 2019

译者按: 为什么偏要用 # 符号?

原文:JavaScript's new #private class fields
•译者:Fundebug

本文采用意译,版权归原作者所有

proposal-class-fieldsproposal-private-methods定义了 Class 的私有属性以及私有方法,这 2 个提案已经处于 Stage 3,这就意味着它们已经基本确定下来了,等待被加入到新的 ECMAScript 版本中。事实上,最新的 Chrome 已经支持了 Class 私有属性。

那么,对于 Class 的私有属性与私有方法,它们究竟是什么呢?它们是怎样工作的?为什么要使用#符号来定义呢?

Class 的私有属性语法如下:

class Point {
 #x;
 #y;
 constructor(x, y) {
  this.#x = x;
  this.#y = y;
 }
 equals(point) {
  return this.#x === point.#x && this.#y === point.#y;
 }
}

我们可以将其语法理解为 2 个部分:

•定义 Class 私有属性
•引用 Class 私有属性

定义 Class 私有属性

私有属性与公共属性的定义方式几乎是一样的,只是需要在属性名称前面添加#符号:

class Foo {
 publicFieldName = 1;
 #privateFieldName = 2;
}

定义私有属性的时候也可以不用赋值:

class Foo {
 #privateFieldName;
}

引用 Class 私有属性

引用私有属性也只需要使用#就好了。

class Foo {
 publicFieldName = 1;
 #privateFieldName = 2;
 add() {
  return this.publicFieldName + this.#privateFieldName;
 }
}

其中,this.#可以简化,去掉 this 也没问题,下面两种写法是等价的:

method() {
 #privateFieldName;
}
method() {
 this.#privateFieldName;
}

在 Class 定义中引用 Class 实例的私有属性

对于私有属性,我们是不可以直接通过 Class 实例来引用的,这也是私有属性的本来含义。但是有一种情况除外,在 Class 定义中,我们可以引用 Class 实例的私有属性:

class Foo {
 #privateValue = 42;
 static getPrivateValue(foo) {
  return foo.#privateValue;
 }
}

Foo.getPrivateValue(new Foo()); // >> 42

其中,foo是Foo的实例,在 Class 定义中,我们可以通过 foo 来引用私有属性#privateValue。

Class 的私有方法

Class 的私有属性是提案proposal-class-fields的一部分,这个提案只关注 Class 的属性,它并没有对 Class 的方法进行任何修改。而 Class 的私有方法是提案proposal-class-fields的一部分。

Class 的私有方法语法如下:

class Foo {
 constructor() {
  this.#method();
 }
 #method() {
  // ...
 }
}

我们也可以将函数赋值给私有属性:

class Foo {
 constructor() {
  this.#method();
 }

 #method = () => {
  // ...
 };
}

封装(隐藏)私有属性

我们不能直接通过 Class 实例引用私有属性,我们只能在 Class 定义中引用它们:

class Foo {
 #bar;
 method() {
 this.#bar; // Works
 }
}
let foo = new Foo();
foo.#bar; // Invalid!

另外,要做到真正的私有的话,我们应该无法检测这个私有属性是否存在,因此,我们需要允许定义同名的公共属性:

class Foo {
 bar = 1; // public bar
 #bar = 2; // private bar
}

如果我们不允许公共属性与私有属性同名,我们则可以通过给同名的公共属性复制监测该私有属性是否存在:

foo.bar = 1; // Error: `bar` is private! (报错,说明私有属性存在)

不报错也行:

foo.bar = 1;
foo.bar; // `undefined` (赋值失败,说明私有属性存在)

对于 subclass 应该同样如此,它也允许公共属性与私有属性同名:

class Foo {
 #fieldName = 1;
}
class Bar extends Foo {
 fieldName = 2; // Works!
}

关于 Class 私有属性的封装,可以参考Why is encapsulation a goal of this proposal?。

为什么使用#符号?

很多人都有一个疑问,为什么 JS 不能学习其他语言,使用private来定义私有属性和私有方法?为什么要使用奇怪的#符号?

使用 private 的话,代码要舒服很多:

class Foo {
 private value;

 equals(foo) {
  return this.value === foo.value;
 }
}

为什么不使用 private 来定义私有属性?

很多语言使用 private 来定义私用属性,如下:

class EnterpriseFoo {
 public bar;
 private baz;
 method() {
  this.bar;
  this.baz;
 }
}

对于这些语言属性,私用属性和公共属性的引用方式是相同的,因此他们可以使用 private 来定义私有属性。

但是,对于 JavaScript 来说,我们不能使用 this.field 来引用私有属性(我接下来会解释原因),我们需要在语法层面上区分私有属性和公共属性。在定义和引用私有属性的时候,使用#符号,私有属性与公共属性可以很好地区分开来。

为什么引用私有属性的时候需要#符号?

引用私有属性的时候,我们需要this.#field,而不是this.field,原因如下:

•因为我们需要封装私有属性,我们需要允许公共属性与私有属性同名,因此私有属性与公共属性的引用方式必须不一样。这一点我们在前文已经详述。
•公共属性可以通过this.field以及this['field']来引用,但是私有属性不能支持this['field']这种方式,否则会破坏私有属性的隐私性,示例如下:

class Dict extends null {
  #data = something_secret;
  add(key, value) {
    this[key] = value;
  }
  get(key) {
    return this[key];
  }
}
new Dict().get("#data"); // 返回私有属性

因此,私有属性与公共属性的引用方式必须不一样,否则会破坏this['field']语法。

•私有属性与公共属性的引用方式一样的话,会导致我们每次都需要去检查属性是公共的还是私有的,这会造成严重的性能问题。

这篇文章遵循Creative Commons Attribution 4.0 International License。

参考

•Why is encapsulation a goal of this proposal?

总结

以上所述是小编给大家介绍的JavaScript 新语法之Class 的私有属性与私有方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
jQuery 跨域访问问题解决方法
Dec 02 Javascript
JQuery对表格进行操作的常用技巧总结
Apr 23 Javascript
跟我学习javascript创建对象(类)的8种方法
Nov 20 Javascript
Backbone中View之间传值的学习心得
Aug 09 Javascript
为jQuery-easyui的tab组件添加右键菜单功能的简单实例
Oct 10 Javascript
巧用Javascript的逻辑运算符
Dec 02 Javascript
Vue.js系列之vue-router(上)(3)
Jan 03 Javascript
angular forEach方法遍历源码解读
Jan 25 Javascript
微信小程序 如何引入外部字体库iconfont的图标
Jan 31 Javascript
浅谈Webpack核心模块tapable解析
Sep 11 Javascript
vue动态改变背景图片demo分享
Sep 13 Javascript
JavaScript中Dom操作实例详解
Jul 08 Javascript
仿ElementUI实现一个Form表单的实现代码
Apr 23 #Javascript
Vue在 Nuxt.js 中重定向 404 页面的方法
Apr 23 #Javascript
vue项目首屏加载时间优化实战
Apr 23 #Javascript
灵活使用console让js调试更简单的方法步骤
Apr 23 #Javascript
详解实现一个通用的“划词高亮”在线笔记功能
Apr 23 #Javascript
Vue源码学习之关于对Array的数据侦听实现
Apr 23 #Javascript
vue的keep-alive中使用EventBus的方法
Apr 23 #Javascript
You might like
php实现可用于mysql,mssql,pg数据库操作类
2014/12/13 PHP
ThinkPHP函数详解之M方法和R方法
2015/09/10 PHP
thinkphp框架page类与bootstrap分页(美化)
2017/06/25 PHP
解决 FireFox 下[使用event很麻烦] 的问题.
2006/08/22 Javascript
小议Function.apply() 之一------(函数的劫持与对象的复制)
2006/11/30 Javascript
js获取html参数及向swf传递参数应用介绍
2013/02/18 Javascript
javascript删除数组元素并且数组长度减小的简单实例
2014/02/14 Javascript
jquery跟js初始化加载的多种方法及区别介绍
2014/04/02 Javascript
javascript学习笔记(五)原型和原型链详解
2014/10/08 Javascript
JQuery菜单效果的两个实例讲解(3)
2015/09/17 Javascript
jQuery插件编写步骤详解
2016/06/03 Javascript
Angular项目中$scope.$apply()方法的使用详解
2017/07/26 Javascript
详解Angular-cli生成组件修改css成less或sass的实例
2017/07/27 Javascript
浅谈vue项目可以从哪些方面进行优化
2018/05/05 Javascript
微信小程序实现两个页面传值的方法分析
2018/12/11 Javascript
Node.js操作系统OS模块用法分析
2019/01/04 Javascript
React-redux实现小案例(todolist)的过程
2019/09/29 Javascript
javascript实现简单打字游戏
2019/10/29 Javascript
Vue v-model组件封装(类似弹窗组件)
2020/01/08 Javascript
vue3为什么要用proxy替代defineProperty
2020/10/19 Javascript
[48:12]Secret vs Optic Supermajor 胜者组 BO3 第三场 6.4
2018/06/05 DOTA
Python整型运算之布尔型、标准整型、长整型操作示例
2017/07/21 Python
安装Python的教程-Windows
2017/07/22 Python
Python基于多线程实现抓取数据存入数据库的方法
2018/06/22 Python
数组保存为txt, npy, csv 文件, 数组遍历enumerate的方法
2018/07/09 Python
pytorch判断是否cuda 判断变量类型方式
2020/06/23 Python
jupyter notebook远程访问不了的问题解决方法
2021/01/11 Python
ET Mall东森购物网:东森严选
2017/03/06 全球购物
文明美德伴我成长演讲稿
2014/05/12 职场文书
家具商场的活动方案
2014/08/16 职场文书
2014学校领导四风对照检查材料思想汇报
2014/09/23 职场文书
行政前台岗位职责
2015/04/16 职场文书
少年的你:世界上没有如果,要在第一次就勇敢的反抗
2019/11/20 职场文书
python通配符之glob模块的使用详解
2021/04/24 Python
使用redis生成唯一编号及原理示例详解
2021/09/15 Redis
使用 Apache 反向代理的设置技巧
2022/01/18 Servers