Javascript 循环中的jQuery变量捕获
我对JS和jQuery的理解非常有限,而且我有C#的背景。但是我知道变量捕获是什么,我知道如果我在循环内捕获一个在循环外声明的变量,每次委托运行时,我都会得到捕获变量的最后一个值,而不是捕获时的值。 然而,这显然不是问题所在,但我仍然收到最后一个值: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
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"
因为现在我们使用的是函数表达式,它们在一步一步的代码中出现,并且行为看起来应该是这样的
让我们回到您的具体示例:一般来说,在循环中创建函数是个坏主意,但有时是必要的。在这些情况下,通常需要像mycreateHandler
函数这样的助手,它位于循环之外,因此可以更好地控制上下文。您可以这样做:
…但你现在不能在野外这样做,因为。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');
});
});