es2022 引入井号(#)语法实现真正私有字段,需在类体顶层声明,仅类内可通过 this.#name 访问,外部访问报错,不参与枚举、序列化或继承,且不可被装饰器或 object.assign 处理。

ES6 class 本身不支持私有属性,井号(#)修饰符是 ES2022(ECMAScript 13)正式引入的语法特性,不是 ES6 的一部分。它提供了真正运行时强制的私有字段封装,无法被外部访问或枚举,也不存在属性名泄露风险。
私有字段的声明与访问规则
私有字段必须在类体顶层显式声明(用 #name),不能动态创建;只能在类的内部方法、getter/setter 或构造函数中通过 this.#name 访问。
- 外部直接读写
instance.#privateField会抛出SyntaxError(静态检查)或TypeError(运行时) - 私有字段不会出现在
for...in、Object.keys()、JSON.stringify()中 - 子类无法继承或访问父类的私有字段,哪怕名称相同也是完全独立的
正确声明和使用私有字段
必须在类定义中预先声明,不可省略;推荐配合私有方法和 getter/setter 暴露受控接口:
class Counter {
#count = 0; // ✅ 正确:顶层声明
#step = 1;
constructor(initial = 0) {
this.#count = initial;
}
increment() {
this.#count += this.#step; // ✅ 类内可访问
}
get value() {
return this.#count; // ✅ 通过 getter 暴露只读视图
}
set step(val) {
if (Number.isInteger(val) && val > 0) {
this.#step = val; // ✅ 私有字段可被受控修改
}
}
}
私有方法与私有 getter/setter
同样以 # 开头,仅限类内部调用,可用于封装复用逻辑或校验:
- 私有方法:用
#methodName() { ... }声明,调用时写this.#methodName() - 私有访问器:如
get #internalData() { return this.#data; },仅用于内部逻辑协调 - 注意:私有方法不能被子类重写,也不参与原型链查找
常见误区与限制
这不是“模拟”或“约定”,而是语言级硬性约束,但也带来一些实际限制:
- ❌ 不能在类外通过任何方式(包括
Reflect.ownKeys、Object.getOwnPropertyDescriptors)获取私有字段名或值 - ❌ 无法对私有字段添加装饰器(如
@watch),因它们不属于常规属性描述符体系 - ❌ 私有字段不参与
Object.assign或展开运算符({...obj}),拷贝时自动忽略 - ✅ 可与公有字段、静态私有字段(
static #field)、私有方法共存,互不干扰











