将匿名函数传递给带有局部变量的命名函数时Javascript中的作用域问题

将匿名函数传递给带有局部变量的命名函数时Javascript中的作用域问题,javascript,scope,attachevent,Javascript,Scope,Attachevent,关于这个标题,我很抱歉,我想不出一个表达方式 以下是场景: 我有一个构建元素的函数: buildSelect(id,cbFunc,...) 在buildSelect中,它执行以下操作: select.attachEvent('onchange',cbFunc); for(var i = 0; i < xs.length; i++) { buildSelect(blah,function(){ CallBack(xs[i],...) },...); } 我还有一个数组: var

关于这个标题,我很抱歉,我想不出一个表达方式

以下是场景:

我有一个构建元素的函数:

buildSelect(id,cbFunc,...)
在buildSelect中,它执行以下操作:

select.attachEvent('onchange',cbFunc);
for(var i = 0; i < xs.length; i++)
{
    buildSelect(blah,function(){ CallBack(xs[i],...) },...);
}
我还有一个数组:

var xs = ['x1','x2','x3'...];
鉴于所有这些,我有一些代码可以做到这一点:

select.attachEvent('onchange',cbFunc);
for(var i = 0; i < xs.length; i++)
{
    buildSelect(blah,function(){ CallBack(xs[i],...) },...);
}
for(变量i=0;i
问题是,当对其中一个选择触发onchange时,它会正确地转到CallBack(),但第一个参数不正确。例如,如果我更改了第三个select,我希望回调()可以用xs[2]调用,而得到一些变化的东西,比如xs[3]或其他东西

如果我将其稍微修改为:

for(var i = 0; i < xs.length; i++)
{
    var xm = xs[i];
    buildSelect(blah,function(){ CallBack(xm,...) },...);
}
for(变量i=0;i
我仍然在CallBack()中得到不正确的值。有些东西告诉我这与范围/闭包有关,但我似乎不知道是什么

我只想让第一个select调用callbackforonchange,第一个参数为xs[0],第二个select调用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 ),...);
}

是的,我认为关闭将有助于:

for(var i = 0, l = xs.length; i < l; i++)
{
    buildSelect(
        blah,
        function(xm){
            return function(){
                CallBack(xm,...)
            };
        }(xs[i]),
        ...
    );
}
for(变量i=0,l=xs.length;i
编辑:我还稍微优化了for循环


编辑:我想我会添加一个解释。您要做的是创建一个匿名函数,它接受一个参数(xm),并直接调用该函数(后面有括号)。此匿名函数还必须将原始函数作为buildSelect()的参数返回。

问题确实与作用域相关——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(变量i=0;i
显然有一个新的
let
关键字可以满足您的需求:

for(var i = 0; i < xs.length; i++)
{
    let xm = xs[i];
    buildSelect(blah,function(){ CallBack(xm,...) },...);
}
for(变量i=0;i
谢谢!我不知道JS没有块作用域。好吧,直到。再次感谢!谢谢的确,调用第二个函数有助于解决问题。@royrules22:不客气。我要指出的是,您还可以利用现有的
buildSelect
功能。只需传入
i
xs[i]
,然后在其中创建处理程序<代码>构建选择(blah,xs[i],…)这可能是最干净的。对不起,我不得不接受另一个问题,但这里接受这个虚拟复选标记!谢谢你的帮助!