2021.05.25(私有方法和私有属性)

私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问。这是常见需求,有利于代
码的封装,但 ES6 不提供,只能通过变通方法模拟实现。

一种做法是在命名上加以区别。

1.  class Widget {
2.
3.  // 公有方法
4.  foo (baz) {
5.  this._bar(baz);
6.  }
7.
8.  // 私有方法
9.  _bar(baz) {
10.  return this.snaf = baz;
11.  }
12.
13.  // ...
14.  }

上面代码中, _bar  方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名
是不保险的,在类的外部,还是可以调用到这个方法。

另一种方法就是索性将私有方法移出模块,因为模块内部的所有方法都是对外可见的。

1.  class Widget {
2.  foo (baz) {
3.  bar.call(this, baz);
4.  }
5.
6.  // ...
7.  }
8.
9.  function bar(baz) {
10.  return this.snaf = baz;
11.  }

上面代码中, foo  是公开方法,内部调用了 bar.call(this, baz)  。这使得 bar  实际上成为了
当前模块的私有方法。

还有一种方法是利用 Symbol  值的唯一性,将私有方法的名字命名为一个 Symbol  值。

1.  const bar = Symbol('bar');
2.  const snaf = Symbol('snaf');
3.
4.  export default class myClass{
5.
6.  // 公有方法
7.  foo(baz) {
8.  this[bar](baz);
9.  }
10.
11.  // 私有方法
12.  [bar](baz) {
13.  return this[snaf] = baz;
14.  }
15.
16.  // ...
17.  };

上面代码中, bar  和 snaf  都是 Symbol  值,一般情况下无法获取到它们,因此达到了私有方法
和私有属性的效果。但是也不是绝对不行, Reflect.ownKeys()  依然可以拿到它们。

1.  const inst = new myClass();
2.
3.  Reflect.ownKeys(myClass.prototype)
4.  // [ 'constructor', 'foo', Symbol(bar) ]

上面代码中,Symbol 值的属性名依然可以从类的外部拿到。

 

目前,有一个提案,为 class  加了私有属性。方法是在属性名之前,使用 #  表示。

1.  class IncreasingCounter {
2.  #count = 0;
3.  get value() {
4.  console.log('Getting the current value!');
5.  return this.#count;
6.  }
7.  increment() {
8.  this.#count++;
9.  }
10.  }

上面代码中, #count  就是私有属性,只能在类的内部使用( this.#count  )。如果在类的外部
使用,就会报错。

1.  const counter = new IncreasingCounter();
2.  counter.#count // 报错
3.  counter.#count = 42 // 报错

上面代码在类的外部,读取私有属性,就会报错。
下面是另一个例子。

1.  class Point {
2.  #x;
3.
4.  constructor(x = 0) {
5.  this.#x = +x;
6.  }
7.
8.  get x() {
9.  return this.#x;
10.  }
11.
12.  set x(value) {
13.  this.#x = +value;
14.  }
15.  }

上面代码中, #x  就是私有属性,在 Point  类之外是读取不到这个属性的。由于井号 #  是属性
名的一部分,使用时必须带有 #  一起使用,所以 #x  和 x  是两个不同的属性。
之所以要引入一个新的前缀 #  表示私有属性,而没有采用 private  关键字,是因为 JavaScript
是一门动态语言,没有类型声明,使用独立的符号似乎是唯一的比较方便可靠的方法,能够准确地区分
一种属性是否为私有属性。另外,Ruby 语言使用 @  表示私有属性,ES6 没有用这个符号而使
用 #  ,是因为 @  已经被留给了 Decorator。

这种写法不仅可以写私有属性,还可以用来写私有方法。

1.  class Foo {
2.  #a;
3.  #b;
4.  constructor(a, b) {
5.  this.#a = a;
6.  this.#b = b;
7.  }
8.  #sum() {
9.  return #a + #b;
10.  }
11.  printSum() {
12.  console.log(this.#sum());
13.  }
14.  }

上面代码中, #sum()  就是一个私有方法。
另外,私有属性也可以设置 getter 和 setter 方法。

1.  class Counter {
2.  #xValue = 0;
3.
4.  constructor() {
5.  super();
6.  // ...
7.  }
8.
9.  get #x() { return #xValue; }
10.  set #x(value) {
11.  this.#xValue = value;
12.  }
13.  }

上面代码中, #x  是一个私有属性,它的读写都通过 get #x()  和 set #x()  来完成。
私有属性不限于从 this  引用,只要是在类的内部,实例也可以引用私有属性。

 

2021-05-25  17:42:28

posted @ 2021-05-25 17:43  铁打的代码流水的bug  阅读(135)  评论(0)    收藏  举报