草案进行阶段
Public and Private Instance Fields Proposal
目前已经处于Stage 3
阶段,这个阶段的内容可以说就是在发布下一个ECMAScript 版本时的正式内容,可以直接使用了。
诞生之前
在引入此语法之前,JavaScript 没有(实际上除非我们采用Babel,否则就没有)真正的私有属性和方法。
这种功能的缺乏导致,之前都通过约定俗成的下划线前缀,来表示该属性和方法为私有属性或私有方法:
.prototype 写法
function User(name) {
this._id = 'xyz';
this.name = name;
}
User.prototype.getUserId = function () {
return this._id;
}
User.prototype._destroy = function () {
this._id = null;
};
const user = new User('Todd Motto');
user._id; // xyz
user.getUserId(); // xyz
user._destroy();
user.getUserId(); // null
即使this._id
与User.prototype._destroy
被认为是私有的(下划线),但实际上任何地方都可以像调用公共属性方法来调用它,因为它们是User对象的一部分。
这就是约定的意思,通过下划线表示其他代码不要调用 私有属性/方法,但实际上是可以随时调用的.
上面我们user._destroy()
在真正被认为是私有的并且可能随时更改的情况下进行调用,因此用户不应使用或依赖我们的私有属性或方法。
现在,随着class
关键字以及已经达到了Stage 3
的提案,已经可以使用了!
让我们将写法从 .prototype 切换到 class 。
Class构造函数
引入class关键字之后,可以得到与前面的**.prototype**示例相同的结果:
class写法
class User {
constructor(name) {
this._id = 'xyz';
this.name = name;
}
getUserId() {
return this._id;
}
_destroy() {
this._id = null;
}
}
const user = new User('Todd Motto');
user._id; // xyz
user.getUserId(); // xyz
user._destroy();
user.getUserId(); // null
tips:注意:class是语法糖,与原型没有本质区别。class在大多数情况下,A会被编译为ES5构造函数,并将属性和方法转换为prototype!
Stage 3
中Class私有属性和方法
通过#
号关键字,将一个Class类的属性设置为私有属性
class User {
/// 声明并赋值
#id = 'xyz';
constructor(name) {
this.name = name;
}
getUserId() {
return this.#id;
}
}
在上面的构造函数中, #id = 'xyz';
这一行,对属性id进行 属性声明并赋值
!这称为属性初始化器语法。
也可以这样做先进行属性声明,再赋值
:
先将私有属性声明为undefined: #id;
,然后在constructor
内进行初始化赋值(Typescript通常采用此种写法,所以推介使用:声明和赋值分开
):
class User {
/// 声明
#id;
constructor(name) {
this.name = name;
/// 赋值
this.#id = 'xyz';
}
getUserId() {
return this.#id;
}
}
需要注意的是,#id;
必须在类本身上声明,否则会出现类似未定义的的错误Private name #id is not defined
。并且属性名称为id,而不是#id。
接下来就可以使用了,并且真正实现了私有:只能在类内引用该属性 #id
,任何其他地方公共属性地访问都将是undefined:
const user = new User('Todd Motto');
user.id; // undefined
user.getUserId(); // xyz
使用私有属性和方法的前提
Stage 3
的内容明年应该就发布了,目前如果你想使用,借助以下工具,并不复杂
- @babel/plugin-proposal-class-properties
- @babel/plugin-proposal-private-methods
- babel-eslint
可以在项目这样安装:
npm install --save-dev @babel/plugin-proposal-class-properties @babel/plugin-proposal-private-methods babel-eslint
接下里创建一个文件.eslintrc.json
//.eslintrc.json
{
"parser": "babel-eslint"
}
它直接使用Babel的内置ESLint解析器
而不是ESLint
来为我们提供更好的控制。
接下来,我们需要创建一个文件.babelrc
看起来像这样的:
// .babelrc
{
"presets": ["@babel/preset-env"],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-private-methods"
]
}
一切顺利,接下来可以第一次在JavaScript中正确使用私有属性和方法了。
为什么使用 # 而不使用 private关键字?
引用私有属性的时候,我们需要这样调用 this.#field,而不是this.field,原因如下:
-
因为我们需要封装私有属性,我们需要允许公共属性与私有属性同名,因此私有属性与公共属性的引用方式必须不一样。
-
公共属性可以通过 this.field 以及 this[‘field’] 来引用,但是私有属性不能支持**this[‘field’]**这种方式,否则会破坏私有属性的隐私性。
------ 如果文章对你有用,感谢右上角 >>>点赞 | 收藏 <<<