闭包是JavaScript实现受保护属性最直接可靠的方式,通过词法作用域隔离变量,仅暴露经校验的get/set方法,禁止外部直连访问;变量须用let/const声明于构造函数内,特权方法需定义在同级作用域。

闭包是 JavaScript 中实现“受保护属性”的最直接、最可靠的方式——它不依赖语法糖,而是利用词法作用域天然切断外部对变量的直连访问。所谓“受保护”,不是完全禁止修改,而是强制所有读写都必须经过你定义的可控入口,从而校验、拦截、转换或记录每一次操作。
把属性声明在构造函数内部,不挂到 this 上
这是最关键的一步。只要变量用 let 或 const 声明在构造函数体中,它就只属于该次实例化的闭包环境,不会出现在实例对象的属性链上。
- ❌ 错误写法:
this.weight = 15→ 外部可随意改:duck.weight = -100 - ✅ 正确写法:
let weight = 15→ 外部无法触达,连console.dir(duck)都看不到它
提供带校验逻辑的 get / set 方法
仅暴露方法,不暴露数据本身。set 方法里可以加类型检查、范围限制、格式验证等,让非法值根本进不来。
- 例如体重只能是正数:
if (value - 例如电话号需符合格式:
if (!/^1[3-9]\d{9}$/.test(value)) throw new Error('Invalid phone') - get 方法也可做脱敏处理,比如返回
'***-****-1234'而非完整号码
避免常见陷阱:箭头函数 vs 普通函数、this 绑定、变量提升
方法定义的位置和方式会影响闭包能否正确捕获私有变量。
- 所有特权方法(如
getWeight)必须定义在构造函数内部,且引用的是同级声明的let/const变量 - 推荐用普通函数写法:
this.getWeight = function() { return weight; };,语义清晰,无 this 风险 - 若用箭头函数:
this.getWeight = () => weight;也完全可行——它自动继承外层词法作用域,无需担心 this - 禁用
var:它会变量提升,可能造成意外交互;一律用let或const
进阶:配合 IIFE 封装全局状态管理器
当需要多个实例共享一套受保护规则(比如统一校验、日志、深拷贝),可把整个构造逻辑包裹在立即执行函数中,对外只暴露干净接口。
- 内部用
const state = {}存储各实例私有数据,key 可以是 Symbol 或 id - set 方法做深拷贝:
state[key] = JSON.parse(JSON.stringify(value)),防引用污染 - get 方法返回冻结副本:
Object.freeze({...state[key]}),进一步限制下游篡改










