前言:方法有很多,但是我们需要择优选择。
1. 命名规范
我们可以通过命名规范实现私有字段,如:下划线
缺点:没有强约束力,我们用了也就用了
class A { _key = 1; } const a = new A(); a._key; // 1
2. Symbol
使用 Symbol,类里用动态属性来设置。
缺点:没有强约束力,也能直接访问到。
const key = Symbol("key"); class A { [key] = 1; m() { return this[key]; } } const a = new A(); a[key]; // 1
3. TS 的 private
使用 TS 的 private。当我们访问属性时,会报一个编译错误。
缺点:这种检查只在编译时态,在运行时态是没错的。可以通过动态属性,绕过编译时态,一样可以拿到 key。
class A { private key = 1; } const a = new A(); a.key; // error
4. ES 的新特性
使用 ES 新特性 #,再去访问#key 就会报错了,无论是编译时,还是运行时。但是因为是新出来的,有兼容性问题。
class A { #key = 1; m() { return this.#key; } }
5. WeakMap
将一个类的私有属性都放在 map 里边。为什么要用 WeakMap ? 避免影响垃圾回收。然后将整个类放到一个模块里,只导出类,那么在外部,就只能通过方法 m() 拿到私有属性了。
const privateFields = new WeakMap(); export class A { constructor() { privateFields.set(this, { key: 1 }); } m() { return privateFields.get(this).key; } }