原型继承本身不提供私有属性机制,私有性必须依靠作用域封闭实现;关键在于用闭包封装构造函数内的变量(如let声明),使其仅对内部方法可见,避免挂到this上,或采用es2022的#私有字段语法。

原型继承本身不提供私有属性机制,私有性得靠作用域封闭来实现,不是靠原型链或访问修饰符。关键在于:把数据藏在函数作用域里,只暴露可控的访问方式。
用闭包封装构造函数内的变量
在构造函数中用 let 或 var 声明变量,它不会挂在 this 上,也不会进入原型链,外部完全无法直接读写:
- 这些变量只对构造函数内部定义的方法(包括挂到
this上的函数)可见 - 子类调用
Parent.call(this)会创建新的闭包环境,不共享父类实例的私有变量 - 例如:
function Person(name) { let _name = name; this.getName = () => _name; }——_name就是真正私有的
避免把私有状态“挂到 this 上”
常见错误是把私有字段模拟成 this._name 这种形式,这本质上是公开的:
- 下划线命名只是约定,不能阻止外部修改或读取
- 一旦被子类或外部代码误改,父类逻辑可能崩溃
- 真正私有必须脱离
this,靠词法作用域锁住
通过方法接口控制访问权限
如果子类需要操作某类内部状态,不要让它直接碰数据,而是由父类提供明确的 getter/setter 或行为方法:
- 比如
this.getSecret = () => secretValue或this.updateConfig = (val) => { if (isValid(val)) _config = val; } - 这样既满足子类使用需求,又保留了校验、副作用控制等封装能力
- 父类可决定哪些状态允许被读、哪些允许被改、改之前要做什么
ES2022 # 私有字段是更现代的选择
如果你用的是 class 语法,#field 是标准级私有字段:
- 它不参与原型继承,子类实例拥有自己独立的
#field,同名也不共享 -
super.#field语法非法,强制你通过父类公开方法间接操作 - 比闭包更直观,且运行时有 TypeError 保护,不是靠“自觉”











