JavaScript 中以 # 开头的字段是运行时强制的真正私有字段,仅类内部可访问,外部不可读写、检测或反射获取,不参与继承,比闭包和 Symbol 更严格,需显式声明并初始化。

JavaScript 中以 # 开头的字段(如 #name)是真正的私有字段,由语言原生保障封装性,外部无法读取、写入或检测其存在,连 in 操作符和 Object.getOwnPropertyNames() 都不可见。
私有字段的访问边界严格限定在类定义内部
只有在同一个 class 的词法作用域内(包括构造函数、普通方法、getter/setter、静态方法),才能访问该类声明的私有字段。跨实例也不行——哪怕两个对象是同一类的实例,一个实例也不能访问另一个实例的私有字段。
- ✅ 允许:
this.#value在类方法中直接读写 - ❌ 禁止:
obj.#value在类外部访问(语法错误) - ❌ 禁止:
otherInstance.#value即使otherInstance是同类型对象 - ❌ 禁止:用
Reflect.get(obj, '#value')或obj['#value']尝试动态访问(根本不存在该属性名)
私有字段不参与原型链,也不被继承
私有字段不属于原型,子类无法通过 super 或任何方式访问父类的私有字段。它只绑定到当前类的实例本身,且完全隔离。
- 子类中定义自己的
#id和父类的#id是两个独立字段,互不影响 -
extends不会带来私有字段的可见性提升,即便子类重写同名方法,也无法触达父类私有状态 - 想让子类“感知”私有逻辑?必须通过受控的公有方法或受保护的 getter(但 getter 本身得是公有的)暴露有限接口
与闭包模拟私有、Symbol 私有字段的本质区别
# 字段是语法级私有,比闭包或 Symbol 更彻底:
立即学习“Java免费学习笔记(深入)”;
- 闭包私有依赖变量作用域,但可通过返回的函数间接暴露;# 字段无任何绕过机制
- Symbol 属性虽不易枚举,但可通过
Object.getOwnPropertySymbols()获取,仍可被反射访问;# 字段对所有反射 API 完全隐身 - TS 中的
private仅是编译时检查,运行时无效;# 是运行时强制约束,不可规避
实际使用建议
适合存放敏感状态、内部缓存、实现细节等不希望被外部干扰的数据。避免滥用:不要只为“看起来私有”而用 #,若需调试或序列化,记得提供显式公有接口(如 toJSON() 方法)。
- 私有字段名必须在类体中显式声明(ES2022+ 要求),不能动态生成
- 支持私有方法和私有 getter/setter:
#getName() {}、get #length() {} - 构造函数中必须初始化私有字段(否则访问时报错),可用
this.#x = value或字段初始化语法#x = defaultValue


















