JavaScript中可用闭包封装变量并仅暴露只读访问器(如getValue)实现私有变量只读控制;进一步通过Object.freeze冻结返回对象、Object.defineProperty设置不可写不可配置getter,或返回深克隆副本,防止篡改与引用泄露。

闭包本身就能天然隔离变量——把变量定义在函数内部,不暴露出去,外部就无法直接访问。但“避免被随意修改”的关键不在闭包是否存在,而在于你如何设计接口、是否做额外防护。
只暴露只读访问器,不提供修改入口
这是最常用也最有效的做法:用闭包封装变量,仅返回 get 类方法,不返回 set 或可写属性。
- 变量定义在函数作用域内(如
let count = 0),外部根本拿不到引用 - 返回对象中只包含
getValue()这类读取方法,没有赋值逻辑 - 即使用户尝试给返回对象加新属性或覆盖方法,原始变量仍不受影响
冻结返回对象,防止属性被篡改
单纯靠闭包不能阻止外部对返回对象本身动手(比如重写 getValue 方法)。用 Object.freeze() 可以锁死对象结构:
return Object.freeze({ get value() { return data; } });- 冻结后无法新增、删除、修改属性,getter 也无法被覆盖(严格模式下赋值会报错)
- 注意:如果返回的是对象或数组等引用类型,需递归冻结其内部,否则深层数据仍可变
用 defineProperty 定义不可配置的 getter
比简单 getter 更强的控制方式:用 Object.defineProperty 显式设置 writable: false 和 configurable: false:
立即学习“Java免费学习笔记(深入)”;
- 这样连属性描述符都不可改,彻底杜绝覆盖或重新定义
- 适合对关键字段(如配置项、ID、初始状态)做硬性保护
- 示例:
Object.defineProperty(obj, 'id', { get: () => id, writable: false, configurable: false })
配合深克隆防止引用泄露
当私有变量是对象或数组时,直接返回引用等于“开门放人”——外部拿到后仍可修改内部属性。稳妥做法是每次读取都返回副本:
- 用
JSON.parse(JSON.stringify(obj))快速浅层克隆(不含函数、undefined、Date 等) - 复杂结构建议用结构化克隆(
structuredClone,现代浏览器支持) - 或者在闭包内维护一份只读快照,读取时返回该快照而非原始引用


















