JavaScript 新语法详解:Class 的私有属性与私有方法
译者按: 为什么偏要用 # 符号?
本文采用意译,版权归原作者所有
proposal-class-fields与proposal-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。
参考
关于Fundebug
Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!

版权声明
转载时请注明作者Fundebug以及本文地址:
[https://blog.fundebug.com/2019/04/23/javascript-class-private-field-and-private-method/
JavaScript 新语法详解:Class 的私有属性与私有方法的更多相关文章
- 从mixin到new和prototype:Javascript原型机制详解
从mixin到new和prototype:Javascript原型机制详解 这是一篇markdown格式的文章,更好的阅读体验请访问我的github,移动端请访问我的博客 继承是为了实现方法的复用 ...
- JavaScript严格模式详解
转载自阮一峰的博客 Javascript 严格模式详解 作者: 阮一峰 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict m ...
- ES6,ES2105核心功能一览,js新特性详解
ES6,ES2105核心功能一览,js新特性详解 过去几年 JavaScript 发生了很大的变化.ES6(ECMAScript 6.ES2105)是 JavaScript 语言的新标准,2015 年 ...
- [转]JavaScript异步机制详解
原文: https://www.jianshu.com/p/4ea4ee713ead --------------------------------------------------------- ...
- Java基础学习总结(33)——Java8 十大新特性详解
Java8 十大新特性详解 本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API ...
- JavaScript(2)---DOM详解
JavaScript(2)---DOM详解 一.DOM概念 什么是DOM DOM全称为文本对象模型(Document Object Model),它定义了所有HTML元素的对象和属性,以及访问他们的方 ...
- es6语法详解
什么是ECMAScript? ECMAScript是浏览器脚本语言的规范,而我们熟知的js语言,如JavaScript则是规范的具体实现.es6就好比Java的jdk. 一.es6语法详解:let声明 ...
- Hadoop Hive sql语法详解
Hadoop Hive sql语法详解 Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构 化的数据文件 ...
- mysql用户授权、数据库权限管理、sql语法详解
mysql用户授权.数据库权限管理.sql语法详解 —— NiceCui 某个数据库所有的权限 ALL 后面+ PRIVILEGES SQL 某个数据库 特定的权限SQL mysql 授权语法 SQL ...
随机推荐
- Oracle12c中PL/SQL(DBMS_SQL)新特性之隐式语句结果(DBMS_SQL.RETURN_RESULT and DBMS_SQL.GET_NEXT_RESULT)
隐式数据结果特性将能简化从其他数据库到Oracle12c存储过程迁移.1. 背景T-SQL中允许查询结果的隐式返回.例如:下面T-SQL存储过程隐式返回查询结果.CREATE PROCEDURE Ge ...
- File文件操作学习总结
1.java.io.file用于表示文件(目录),也就是说程序员可以通过File类在程序中操作硬盘上的文件和目录, 2.File类只能用于表示文件(目录)的信息(名称和大小),不能对文件内容进行访问. ...
- restTemplate设置访问超时
(一)RestTemplate 客户端 1.RestTemplate 是Spring的封装,需要spring的包 spring-web-3.0.7.RELEASE.jar 2.客户端代码: /** * ...
- eclipse汉化链接
百度百科 https://jingyan.baidu.com/article/4b07be3cb1864e48b380f315.html 博客园:http://blog.csdn.net/sunny_ ...
- 架构选型之Nodejs与Java
前言: 身边越来越多的同事谈论Nodejs,谈其异步IO.事件回调.前后台统一一门语言,创业的朋友的第一个创业项目也选择了Nodejs,期望能够使用一种语言节省成本快速完成需求开发.与其他项目组的同事 ...
- tk.mybatis.mapper.provider.SpecialProvider.<init>()
2017-03-26 23:44:29.192 ERROR 48392 --- [p-nio-80-exec-5] c.t.global.exception.GlobalExHandler : nes ...
- Layer组件多个iframe弹出层打开与关闭及参数传递
一.Layer简介 Layer是一款近年来备受青睐的web弹层组件,基于jquery,易用.实用,兼容包括IE6在内的所有主流浏览器,拥有丰富强大的可自定义的功能. Layer官网地址:http:// ...
- 11. 将博客部署到tomcat上
springboot项目既可以以jar运行,也可以做成war包放到服务器上,因为我的博客项目涉及到文件上传,所以按照jar的方式就不可行,需要部署到tomcat上,具体做法如下:1. 修改pom.xm ...
- public_handers.go
package],,) ],,) ]:],,);:],],,) ) ]],,) )) ,) )) if etagMatch { w.WriteHeader(ht ...
- req_params.go
, fmt.Sprintf("%s: closing %s", proto, listener.Addr())) }