当使用局部变量将匿名函数传递给命名函数时,Javascript中的范围问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当使用局部变量将匿名函数传递给命名函数时,Javascript中的范围问题相关的知识,希望对你有一定的参考价值。
抱歉标题 - 我无法找到一种方法来表达它。
这是场景:
我有一个构建元素的函数:
buildSelect(id,cbFunc,...)
在buildSelect内部执行此操作:
select.attachEvent('onchange',cbFunc);
我也有一个数组:
var xs = ['x1','x2','x3'...];
考虑到所有这些,我有一些代码可以做到这一点:
for(var i = 0; i < xs.length; i++)
{
buildSelect(blah,function(){ CallBack(xs[i],...) },...);
}
问题是当onchange在其中一个选择上被触发时,它正确地转到CallBack(),但第一个参数是不正确的。例如,如果我改变第三个选择,我期望用xs [2]调用CallBack(),而不是像xs [3]或其他东西那样得到一些不同的东西。
如果我稍微修改它:
for(var i = 0; i < xs.length; i++)
{
var xm = xs[i];
buildSelect(blah,function(){ CallBack(xm,...) },...);
}
我在CallBack()中仍然得到不正确的值。有些东西告诉我这是范围/关闭相关但我似乎无法弄清楚是什么。
我只想让第一个选择调用CallBack for onchange,第一个参数为xs [0],第二个选择xs [1],依此类推。我在这里做错了什么?
我应该澄清xs是一个全局变量。
谢谢
您需要通过在自己的范围内关闭它来捕获xm
值。
要做到这一点,需要单独的函数调用:
buildCallback( curr_xm ) {
// this function will refer to the `xm` member passed in
return function(){ CallBack(curr_xm,...) },...);
}
for(var i = 0; i < xs.length; i++)
{
var xm = xs[ i ];
buildSelect(blah,buildCallback( xm ),...);
}
现在回调引用的xm
是你传递给buildCallback
的那个。
如果你需要保留i
的其他用途,你可以发送它:
buildCallback( curr_i ) {
// this function will refer to the `i` value passed in
return function(){ CallBack( xs[ curr_i ],...) },...);
}
for(var i = 0; i < xs.length; i++)
{
buildSelect(blah,buildCallback( i ),...);
}
问题确实与范围相关 - javascript只有函数作用域,而不是块作用域或循环作用域。变量i
和xm
只有一个实例,这些变量的值随循环的进展而变化。循环完成后,您只剩下它们持有的最后一个值。您的匿名函数会捕获变量本身,而不是它们的值。
要捕获变量的实际值,您需要另一个可以捕获局部变量的函数:
function makeCallback(value) {
return function() { CallBack(value, ...) };
}
每次调用makeCallback
都会得到一个value
变量的新实例,如果你捕获了这个变量,你基本上会捕获这个值:
for(var i = 0; i < xs.length; i++)
{
buildSelect(blah,makeCallback(xs[i]),...);
}
是的,我认为关闭会有所帮助:
for(var i = 0, l = xs.length; i < l; i++)
{
buildSelect(
blah,
function(xm){
return function(){
CallBack(xm,...)
};
}(xs[i]),
...
);
}
编辑:我也略微优化了你的for循环。
编辑:我想我会添加一个解释。你正在做的是创建一个匿名函数,它接受一个参数(xm)并立即调用函数(后面的括号)。此匿名函数还必须将原始函数作为buildSelect()的参数返回。
显然有一个新的let
关键字可以满足您的需求:
for(var i = 0; i < xs.length; i++)
{
let xm = xs[i];
buildSelect(blah,function(){ CallBack(xm,...) },...);
}
以上是关于当使用局部变量将匿名函数传递给命名函数时,Javascript中的范围问题的主要内容,如果未能解决你的问题,请参考以下文章