JavaScript不安全变量引用问题:如何修正循环中属性访问错误?
问题分析与解决方案
这问题我之前踩过坑!核心原因是箭头函数会捕获外层作用域的变量引用,而不是每次循环时的变量快照。你用var声明的key是函数级作用域的变量,整个循环里只有一个key的引用——循环结束后,key的值停在了最后一个属性名key2,所以不管你调用哪个get(),都会取到values[key2]的值,这就是为什么实际输出是val2。
下面给你几种可行的修改方案:
方案1:用let声明循环变量
let会在每次循环迭代时创建一个块级作用域的新变量,这样箭头函数捕获的就是当前迭代的那个key的独立引用:
var values = { "key1": "val1", "key2": "val2" }; const properties = {}; // 把var改成let,让每次循环都有独立的key变量 for (let key in values) { properties[key] = { get: () => values[key], set: (val) => { values[key] = val } }; } console.log(properties["key1"].get()); // 输出val1,符合预期
方案2:用立即执行函数表达式(IIFE)隔离作用域
如果你的环境不能用ES6的let,可以用IIFE手动创建独立作用域,把当前循环的key值传进去保存:
var values = { "key1": "val1", "key2": "val2" }; const properties = {}; for (var key in values) { // 用IIFE捕获当前key的快照 (function(currentKey) { properties[currentKey] = { get: () => values[currentKey], set: (val) => { values[currentKey] = val } }; })(key); } console.log(properties["key1"].get()); // 输出val1
方案3:用Object.entries()配合forEach迭代
forEach的回调函数会在每次迭代时接收独立的参数,天然隔离了作用域,写法也更简洁:
var values = { "key1": "val1", "key2": "val2" }; const properties = {}; // 解构出每个键值对的key Object.entries(values).forEach(([key, _]) => { properties[key] = { get: () => values[key], set: (val) => { values[key] = val } }; }); console.log(properties["key1"].get()); // 输出val1
内容的提问来源于stack exchange,提问作者Qwe Qwe
相关产品推荐
相关产品推荐

