Javascript 循环中的jQuery变量捕获

Javascript 循环中的jQuery变量捕获,javascript,jquery,variables,Javascript,Jquery,Variables,我对JS和jQuery的理解非常有限,而且我有C#的背景。但是我知道变量捕获是什么,我知道如果我在循环内捕获一个在循环外声明的变量,每次委托运行时,我都会得到捕获变量的最后一个值,而不是捕获时的值。 然而,这显然不是问题所在,但我仍然收到最后一个值: for (var i = 0; i < dialogs.length; i++) { var dialog_button = dialogs[i]; var ix_parts = $(dialog_button).attr

我对JS和jQuery的理解非常有限,而且我有C#的背景。但是我知道变量捕获是什么,我知道如果我在循环内捕获一个在循环外声明的变量,每次委托运行时,我都会得到捕获变量的最后一个值,而不是捕获时的值。 然而,这显然不是问题所在,但我仍然收到最后一个值:

for (var i = 0; i < dialogs.length; i++) {

    var dialog_button = dialogs[i];

    var ix_parts = $(dialog_button).attr("id").split("_");
    var index_tag = ix_parts[1];
    var dialog_panel = $(dialog_panel_selector.replace("$ix$", index_tag));
     $(dialog_button).click(function (event) {
            $(dialog_panel).dialog('open');
            return false;
        });
for(变量i=0;i
}

由于dialog_按钮是在循环的作用域内声明的,因此我希望在click处理程序内收到正确的值。

JS是否做了一些不同的事情?

JavaScript没有块作用域,只有函数作用域(以及全局作用域)。闭包接收对变量的实时引用,因此事件处理程序函数(闭包)将始终看到分配给
dialog\u按钮的最后一个值

在您描述的特定情况下,您最好使用jQuery的函数,而不是
for
循环(谢谢@Esailija,值得一提的是,我在@Esailija的建议中添加了它,因为它是在这种特定情况下更好的解决方案):

…因为现在,我们传递的每个函数调用
$。每个
都有自己独特的
对话框按钮
参数,因此每个生成的函数(闭包)都会关闭自己的副本,我们不会遇到为变量分配新值的问题

我建议使用jQuery函数,因为您已经在使用jQuery了,所以可以确定它是可用的。从ECMAScript5开始,有一个本机函数可以做很多相同的事情,但不是所有的引擎都有它

在上述情况不符合要求的情况下,还有另一种方法。它还包括一个相当深入的讨论,讨论发生了什么,为什么,以及如何控制它,使其对您有利:

您最好使用一个创建事件处理程序的函数,如下所示(我假设所有这些都在一个函数中):

…或者,如果您需要在其他地方执行相同的操作,您可以将其移出一个级别:

function createDialogs() {
    for (var i = 0; i < dialogs.length; i++) {

        var dialog_button = dialogs[i];

        var ix_parts = $(dialog_button).attr("id").split("_");
        var index_tag = ix_parts[1];
        var dialog_panel = $(dialog_panel_selector.replace("$ix$", index_tag));
        $(dialog_button).click(createHandler(dialog_button));
    }
}

function createHandler(dlg) {
    return function (event) {
        $(dlg).dialog('open');
        return false;
    };
}
下面是分配给变量的函数表达式:

var foo = function() {
};
下面是另一个函数表达式,这次用作对象文字中的属性初始值设定项:

var obj = {
    foo: function() {
         }
};
另一个函数表达式,这次作为参数传递到函数中:

bar(function() {
});
正如您所看到的,它们之间的区别在于函数声明是独立的,而函数表达式在包含表达式中用作右端值-作为赋值(
=
)或初始值设定项(
)的右端,或作为参数传递到函数中

函数声明在创建包含它们的作用域时进行处理,然后再执行任何分步代码。因此:

function bar() {

    function foo() {
    }

    return foo;
}
…当调用
bar
时,在任何分步代码运行之前,将创建
foo
函数。然后才是逐步运行代码,在本例中,它返回对
foo
函数的引用。因此,上述内容完全等同于此:

function bar() {

    return foo;

    function foo() {
    }
}
即使它看起来像
foo
return
语句中不应该存在,但它确实存在

由于函数声明发生在分步代码之前,因此它们不能在控制流语句中:

function bar(condition) {
    if (condition) {
        function foo() {    // <== INVALID
            return alert("A");
        }
    }
    else {
        function foo() {    // <== INVALID
            return alert("B");
        }
    }

    return foo;
}
var f = bar(true);
f(); // alerts what?
这里,
bar
返回
undefined
,因为在
return
语句中,
foo
undefined
,当然下面的赋值语句从未出现过。类似地,这是有效的,其行为定义明确:

function bar(condition) {
    var foo;

    if (condition) {
        foo = function() {
            return alert("A");
        };
    }
    else {
        foo = function() {
            return alert("B");
        };
    }

    return foo;
}
var f = bar(true);
f(); // alerts "A"
f = bar(false);
f(); // alerts "B"
因为现在我们使用的是函数表达式,它们在一步一步的代码中出现,并且行为看起来应该是这样的

让我们回到您的具体示例:一般来说,在循环中创建函数是个坏主意,但有时是必要的。在这些情况下,通常需要像my
createHandler
函数这样的助手,它位于循环之外,因此可以更好地控制上下文。您可以这样做:

…但你现在不能在野外这样做,因为。IE8及以下版本将两次看到该构造,一次作为函数声明,然后再次作为函数表达式。它确实会创建两个函数对象,这可能会引起各种各样的麻烦。:-)

用于
循环的闭包和

是的,它正在做一些不同的事情,以下(和)证明了这一点:


有帮助吗?你有什么问题吗?

我想你应该这样做:
$(对话框按钮)。点击((createHandler(对话框按钮))
您需要在开始时执行func,以便它将为您提供一个新的funcexecute@RoyiNamir当前位置我所拥有的是正确的。您的代码将调用
createHandler
来创建处理程序函数,然后立即执行返回的处理程序函数,将其返回值传递到
click
,这不是我们想要的。我们希望调用
createHandler
来创建函数对象并返回对它的引用(不调用它),然后将引用传递到
click
,以便将其设置为事件处理程序。当单击发生时,将调用处理程序函数(确保它不在任何分支内,它必须位于函数的顶层)->您能详细说明一下吗?我已经在for循环中声明了这个函数,它似乎正在工作!我做错什么了吗?@TDaver:在JavaScript中,函数声明和
function bar() {

    function foo() {
    }

    return foo;
}
function bar() {

    return foo;

    function foo() {
    }
}
function bar(condition) {
    if (condition) {
        function foo() {    // <== INVALID
            return alert("A");
        }
    }
    else {
        function foo() {    // <== INVALID
            return alert("B");
        }
    }

    return foo;
}
var f = bar(true);
f(); // alerts what?
function bar() {
    var foo;

    return foo;

    foo = function() {
    };
}
function bar(condition) {
    var foo;

    if (condition) {
        foo = function() {
            return alert("A");
        };
    }
    else {
        foo = function() {
            return alert("B");
        };
    }

    return foo;
}
var f = bar(true);
f(); // alerts "A"
f = bar(false);
f(); // alerts "B"
for (var i = 0; i < dialogs.length; i++) {

    var dialog_button = dialogs[i];

    var ix_parts = $(dialog_button).attr("id").split("_");
    var index_tag = ix_parts[1];
    var dialog_panel = $(dialog_panel_selector.replace("$ix$", index_tag));
    $(dialog_button).click((function(dlg) {
        return function (event) {
            $(dlg).dialog('open');
            return false;
        };
    })(dialog_button));
}
var f = function foo() { // <== WARNING, see below
};
var tests = [1,2,3,4,5];

for (var i=0; i<tests.length; i++){
    var test = tests[i];
};

alert(test);
jQuery.each(dialogs, function(ind, dialog){
    var dialog_button = $(dialog);
    var index_tag = dialog_button.attr("id").split("_")[1];
    var dialog_panel = $(dialog_panel_selector.replace("$ix$", index_tag));
    dialog_button.click(function(event){
        event.preventDefault();
        dialog_panel.dialog('open');
    });
});