闭包是构造函数中模拟私有成员最常用方式:通过函数作用域隔离变量,确保外部无法读取或修改;每次调用生成独立作用域,实例间私有状态完全隔离,且不暴露于属性遍历与序列化。

闭包在构造函数中是最常用、最直观的私有成员模拟方式:它不依赖新语法,靠函数作用域天然隔离变量,让外部既不能读取、也不能修改那些被包裹的值——这才是运行时意义上的“真正私有”。
构造函数内声明 + 闭包方法暴露
私有数据放在构造函数局部作用域里,不挂到 this 上;所有能操作它的方法,都定义在同一个作用域内,并返回为公有接口:
- 每次调用构造函数都会生成独立作用域,确保不同实例的私有状态完全隔离(比如 c1.count 和 c2.count 互不影响)
- 私有变量不会出现在实例属性中,console.log(obj) 看不到,JSON.stringify() 序列化不出,for...in 或 Object.keys() 都遍历不到
- 外部无法通过点号、方括号或反射 API(如 Object.getOwnPropertyNames())访问,只能走你开放的 getter/setter 方法
避免重复创建函数:工厂模式优化
如果方法逻辑复杂或实例数量多,可把方法抽离出来复用,同时保持私有性:
- 用工厂函数持有私有状态(如 state = { count: 0 }),再返回一组箭头函数或绑定函数
- 所有实例共享同一份方法代码,节省内存;而私有数据仍由闭包独占,不被其他实例干扰
- 注意方法内部不能依赖 this,必须显式传入或闭包捕获状态对象
结合 Symbol 实现“约定式私有”字段
想更贴近类写法,又保留闭包控制权,可用 Symbol 作为键名挂载私有数据到实例上:
- 用 Symbol('count') 创建唯一不可枚举的键,防止命名冲突和意外覆盖
- 私有值存在实例自身,但因 Symbol 键不可枚举,常规遍历看不到;配合闭包内的方法访问,形成封装闭环
- 需注意:它仍可通过 Object.getOwnPropertySymbols() 获取,属于语义约定而非强制保护
与 WeakMap 配合支持原型方法
当必须用 class 或原型链(比如要继承、要用 new)时,WeakMap 是平衡私有性和面向对象风格的关键:
- 用 WeakMap 存储 this → 私有数据对象 的映射,键是实例本身,值是真正私有的状态
- 原型上的方法通过 privateData.get(this) 拿到对应状态,实现方法复用 + 状态隔离
- WeakMap 的键弱引用特性避免内存泄漏,且私有数据彻底脱离实例属性树











