如何为从其他对象动态添加的属性正确定义Getter/Setter?
问题分析与解决方案:Getter/Setter 闭包陷阱
你遇到的是JavaScript里循环闭包的变量捕获问题,这也是很多开发者刚接触闭包时容易踩的经典坑。
问题根源
你的代码中,for循环里用var声明的key是函数级作用域变量——整个循环过程中只有这一个key存在。当循环结束时,key的值会停留在最后一个遍历到的属性名(也就是name)。而你定义的getter和setter函数都是闭包,它们共享这个key变量,所以所有属性的读写操作最终都会指向values['name'],这就导致了设置Master.id=234后,读取Master.id返回的却是New master。
两种可行的修复方案
方案1:用立即执行函数(IIFE)创建独立作用域
通过IIFE把每次循环的key值封装到独立作用域里,让每个getter/setter都引用自己作用域内的变量:
var params = { id: 123, name: 'Old master' }; var Master = new function() { var values = {}; for(var key in params) { // 用IIFE捕获当前循环的key值,绑定到currentKey上 (function(currentKey) { Object.defineProperty(this, currentKey, { enumerable: true, set: function(value) { values[currentKey] = value; }, get: function() { return values[currentKey]; } }); }).call(this, key); } return this; }() Master.id = 234; Master.name = 'New master'; console.log(Master.id); // 输出 234 console.log(Master.name); // 输出 New master
方案2:用ES6的let声明块级作用域变量
如果你的环境支持ES6,直接用let声明key就可以解决问题。let会在每次循环时创建一个全新的变量实例,每个getter/setter都会捕获当前循环的key:
var params = { id: 123, name: 'Old master' }; var Master = new function() { var values = {}; // let声明的key是块级作用域,每次循环都有独立的变量 for(let key in params) { Object.defineProperty(this, key, { enumerable: true, set: function(value) { values[key] = value; }, get: function() { return values[key]; } }); } return this; }() Master.id = 234; Master.name = 'New master'; console.log(Master.id); // 输出 234 console.log(Master.name); // 输出 New master
可行性说明
完全可行!这是JavaScript中处理循环闭包的标准场景,只要解决了变量共享的问题,就能为每个属性绑定独立的getter/setter,实现对values中对应项的正确读写。
内容的提问来源于stack exchange,提问作者proudbird
相关产品推荐
相关产品推荐

