Javascript 私有属性和方法

草案进行阶段

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._idUser.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’]**这种方式,否则会破坏私有属性的隐私性。

------ 如果文章对你有用,感谢右上角 >>>点赞 | 收藏 <<<

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值