1

我只需要使用部分应用程序将数据传递给回调,我发现我需要一个间接层来防止循环的后续运行更改我传递给回调的数据。

在这里查看一个非常简单的工作示例:http: //jsfiddle.net/s5gVj/

(如果 jsfiddle 是不言自明的,请随时直接跳到下面的问题)

没有间接

这将始终将标签设置为“按下按钮 1”。

无论按下哪个按钮,都会发生这种情况。

for(var i = 0 ; i < buttons.length ; i++)
{
    var buttonID = i;
    $(buttons[i]).click(   
        function(e)
        {
            $("label").html("Button " + buttonID + " pressed.");
        });
}

间接地,通过函数

同时,在中间使用一个函数可以解决问题

对于第一个按钮,结果将是“按下按钮 0”

对于第二个按钮,它将是“按下按钮 1”。

var buttonClickHandlerWithID = 
    function(buttonID)
    {
        return function(e)
        {
            $("label").html("Button " + buttonID + " pressed.");
        }
    }

for(var i = 0 ; i < buttons.length ; i++)
{
    $(buttons[i]).click(buttonClickHandlerWithID(i));
}


为什么会这样?函数调用是否有什么特别之处可以确保变量被复制,从而不再引用相同的数据,或者还有其他事情发生?

我希望在每次迭代时重新创建在 for 循环中声明的变量,因此每次迭代都是分开的,但我想不是这样吗?

4

2 回答 2

2

JavaScript 只有函数作用域。函数中任何位置的所有var声明(当然嵌套函数内部除外)都被视为出现在函数顶部。嵌套{ ... }块没有自己的作用域,这与 C++ 和 Java 等有很大的不同。

于 2014-06-30T16:10:07.253 回答
1

就像 Pointy 回答的那样,javascript 中只有函数作用域,这意味着i您的代码中的作用域在循环之外,并且稍后引用时(单击时)将是for循环完成后它最终的结果。

如果您使用 jquery.each()而不是for,您将获得本地范围,因为它需要一个函数作为回调。

var i = 0;
var directButtons = $("button.direct");

// jquerys each method takes a function callback
directButtons.each(function () {
    i++;
    // since this is inside a function
    var buttonID = i; // buttonID will be locally scoped

    $(this).click(function (e) {
        // this inner function "close over" (google "javascript closure") and
        // remembers the value of buttonID in the .each() loop
        $("label").html("Button " + buttonID + " pressed. " +
          "'i' will be whatever it ended up after the .each() is finished: " + i);
    });
});

http://jsfiddle.net/s5gVj/3/

另请查看fixthesejquery.com的幻灯片 55


您还可以使用立即调用函数表达式来解决此问题(请参阅标题为“使用闭包保存状态”的部分):

var directButtons = $("button.direct");

for(var i = 0 ; i < directButtons.length ; i++){
    (function(buttonID){
        // buttonID is now scoped to this function
        $(directButtons[buttonID]).click(function (e) {
            $("label.direct").html("Button " + buttonID + " pressed. , 'i' is always " + i);
        });
    })(i); // call the function immediately, supply the value of "i" as parameter
}

http://jsfiddle.net/s5gVj/4/

于 2014-06-30T16:29:12.427 回答