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

浙公网安备 33010602011771号