Nodejs 匿名函数引用外部变量是引用类型的问题
Nodejs 匿名函数引用外部变量是引用类型的问题
var obj = {};
var funNames = [‘get’, ‘set’];
for(var item in funNames){
var funName = funNames[item];
obj[funName] = function(){
console.log(funName);
}
}
obj.get();
obj.set();
最后两个都输出 set, 我想实现的是一个输出 get, 一个输出set
Node.js 匿名函数引用外部变量是引用类型的问题
在 JavaScript 中,尤其是使用 Node.js 时,匿名函数常常会引用外部的变量。然而,这可能会导致一些意外的行为,特别是在循环中定义函数时。让我们通过一个具体的例子来说明这个问题,并提供解决方案。
示例代码
var obj = {};
var funNames = ['get', 'set'];
for (var item in funNames) {
var funName = funNames[item];
obj[funName] = function() {
console.log(funName);
};
}
obj.get(); // 输出 "set"
obj.set(); // 输出 "set"
在这个例子中,我们期望 obj.get()
输出 "get"
而 obj.set()
输出 "set"
。但实际上,两者都输出 "set"
。这是因为循环中的 funName
变量在每次迭代中都被更新,而函数引用的是同一个 funName
变量。因此,在循环结束后,所有函数都引用了最后一次赋值后的 funName
值。
解决方案
为了确保每个函数都能正确地引用到它们在循环中对应的值,可以使用闭包或者立即执行函数表达式(IIFE)来捕获当前的 funName
值。
使用闭包
var obj = {};
var funNames = ['get', 'set'];
for (var item in funNames) {
var funName = funNames[item];
(function(fn) { // 创建一个新的作用域
obj[fn] = function() {
console.log(fn);
};
})(funName); // 立即执行函数表达式
}
obj.get(); // 输出 "get"
obj.set(); // 输出 "set"
使用 let
声明
另一种更简洁的方法是使用 let
关键字声明变量,这样可以在每次迭代中创建一个新的块级作用域,从而避免引用问题。
var obj = {};
var funNames = ['get', 'set'];
for (let item in funNames) { // 使用 let 替换 var
let funName = funNames[item];
obj[funName] = function() {
console.log(funName);
};
}
obj.get(); // 输出 "get"
obj.set(); // 输出 "set"
通过以上两种方法,我们可以确保每个函数都能正确地引用到它们在循环中对应的 funName
值。
用闭包可以实现
var obj = {};
var funNames = ['get', 'set'];
for(var item in funNames){
var funName = funNames[item];
function some(funName){
return function() {
console.log(funName);
}
}
obj[funName] = some(funName);
}
obj.get();
obj.set();
var obj = {};
var funNames = ['get', 'set'];
for(var item in funNames){
var funName = funNames[item];
//动态生成function
obj[funName] = new Function("console.log('" + funName + "');");
}
obj.get();
obj.set();
可以实现我的功能 非常感谢.
var obj = {};
var funNames = ['get', 'set'];
funNames.forEach(function(funName) {
obj[funName] = function(){
console.log(funName);
}
});
obj.get();
obj.set();
这个最简洁最有效
在这个问题中,问题的核心在于匿名函数对外部变量的引用方式。由于funName
是在循环中定义的,当循环结束后,funName
的值会变成循环的最后一个值,即'set'
。因此,在调用obj.get()
和obj.set()
时,它们都会输出set
。
这是因为JavaScript中的闭包捕获的是变量的引用,而不是变量在当前作用域内的值。所以在创建匿名函数时,它实际上引用的是同一个funName
变量。当循环结束时,funName
的值为'set'
,所以所有匿名函数都打印出'set'
。
解决方案
可以通过立即执行函数表达式(IIFE)来捕获每个迭代中的funName
变量的当前值:
var obj = {};
var funNames = ['get', 'set'];
for (var item in funNames) {
(function(funName) { // IIFE
obj[funName] = function() {
console.log(funName);
}
})(funNames[item]);
}
obj.get(); // 输出 "get"
obj.set(); // 输出 "set"
解释
通过使用IIFE,我们为每次迭代创建了一个新的作用域,并将funName
作为参数传递给该作用域。这样,每个匿名函数都有自己的funName
副本,而不是共享同一个变量。因此,当调用obj.get()
和obj.set()
时,它们会分别输出get
和set
。
这种方法确保了每个匿名函数能够访问到循环中正确迭代的变量值,从而避免了引用类型导致的问题。