前言:方法有很多,但是我们需要择优选择。
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;}
}