使用Object.defineProperty定义属性时生成冗余变量_m的问题咨询
解决Object.defineProperty定义属性时的冗余变量问题
嘿,我完全懂你遇到的困扰——用Object.defineProperty定义存取器属性时,不得不额外声明一个像_m这样的“备份变量”,最后这个变量还会暴露在对象上,显得很冗余,对吧?
其实这背后的原因是:存取器属性(get/set)本身并不存储值,它只是提供了读取和修改值的接口,所以必须依赖一个单独的变量来保存实际数据。如果直接在get里返回this.m,就会无限递归调用getter,陷入死循环。
不过我们有几种方法可以避免这个冗余变量暴露在对象的公共属性里,下面给你一一拆解:
1. 用闭包封装私有变量
通过立即执行函数创建闭包,把备份变量藏在闭包内部,外部完全访问不到:
var a = (function() { // 这个_m只存在于闭包中,外部无法直接访问 let _m; return { get m() { return _m; }, set m(val) { _m = val; console.log('val', val); } }; })(); // 测试一下 a.m = 123; // 输出 "val 123" console.log(a.m); // 123 console.log(a._m); // undefined,外部看不到这个变量
这种方法的好处是简单直接,适合单个对象的场景。
2. 用WeakMap存储私有数据
如果需要给多个对象定义类似的私有属性,WeakMap是个不错的选择——它的键是对象,值是私有数据,而且不会阻止对象被垃圾回收:
// 把WeakMap放在模块内部,外部无法访问 const privateData = new WeakMap(); var a = {}; // 给a对象初始化私有数据 privateData.set(a, { m: undefined }); Object.defineProperty(a, 'm', { get() { return privateData.get(a).m; }, set(val) { privateData.get(a).m = val; console.log('val', val); } }); console.log(a.m = 456); // 输出 "val 456" console.log(a._m); // undefined,对象上没有冗余属性
3. ES6+原生私有字段(推荐)
现在现代浏览器已经支持原生的私有字段语法(#开头),这是最简洁也最符合JS规范的方案:
类中的私有字段
class MyObject { // #m是真正的私有字段,外部完全不可访问 #m; get m() { return this.#m; } set m(val) { this.#m = val; console.log('val', val); } } const a = new MyObject(); a.m = 789; // 输出 "val 789" console.log(a.m); // 789 console.log(a.#m); // 语法错误!外部无法访问私有字段
对象字面量中的私有字段
最新的浏览器也支持在对象字面量里直接定义私有字段:
const a = { #m: undefined, get m() { return this.#m; }, set m(val) { this.#m = val; console.log('val', val); } };
这种方式的私有字段不会出现在对象的Object.keys()或for...in遍历中,真正实现了数据的私有性,完美解决冗余变量的问题。
内容的提问来源于stack exchange,提问作者alexBear
相关产品推荐
相关产品推荐

