javascript中无真正私有属性(es2022前),靠命名约定或闭包模拟,子类无法继承或访问;es2022的#语法实现严格私有,仅类内部可访问,子类须通过父类提供的受控接口操作。

JavaScript 中没有真正的“私有属性”概念(ES2022 之前),所谓“私有”通常靠命名约定(如 _name)或闭包模拟实现,因此父类的私有属性默认不会被子类继承,也无法在子类中直接访问。ES2022 引入的 # 语法(哈希私有字段)提供了真正私有的能力,但其访问限制更严格:仅限于声明它的类内部。
传统下划线约定的“伪私有”属性
这类属性实际是公有的,只是开发者约定不直接使用:
- 子类构造函数中可通过
this._privateField访问(因为仍是普通属性) - 但这种访问违背封装意图,容易导致耦合和维护风险
- 例如:
class Parent { constructor() { this._id = 42; } },子类可读写this._id
闭包模拟的私有数据(如在构造函数内用 let 声明)
这种模式下,私有数据完全脱离实例对象,仅闭包内可触达:
- 子类无法访问,甚至无法感知其存在
- 父类需通过公有方法暴露受控操作(如
getId()、updateId()) - 子类只能调用这些方法,不能绕过逻辑直接修改底层值
ES2022 # 私有字段(真正私有)
使用 #field 声明的字段具有严格的词法作用域限制:
- 仅在定义它的类体内部可访问(包括其原型方法)
- 子类中任何位置(构造函数、方法、getter)都不可读写该 # 字段
- 试图访问会抛出
SyntaxError(静态检查)或TypeError(运行时) - 必须由父类提供受保护的接口(如
protectedGet#value()或protectedUpdate#value())供子类安全使用
推荐实践:用受控接口代替直接访问
无论采用哪种“私有”方式,都应避免子类依赖父类内部实现细节:
- 父类暴露
getXXX()/setXXX(value)方法,并在其中做校验或副作用处理 - 子类通过
super.getXXX()获取,或调用super.setXXX()修改 - 若需子类自定义行为,可用模板方法模式:父类定义
process()并调用抽象的beforeProcess()(由子类实现)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











