可能访问修改后的关闭问题...如何打败?

时间:2009-08-21 16:53:27

标签: javascript closures

出于某种原因,无论如何,pageNumber最终成为loopCounter循环中的最后一个值。现在我明白如果我在闭包本身直接使用loopCounter,但我不是。从下面的代码中可以看出,我在闭包中创建了一个新变量来获取loopCounter的当前值。

我唯一可以想到的是(假设javascript将所有东西视为引用类型)pageNumber正在引用loopCounter,所以无论我创建一个新的pageNumber有多少次,它总是指向loopCounter对象。因此,loopCounter最终得到的值将是任何pageNumber将指向的值。

如何让它不指向loopCounter但是每次迭代创建一个新的pageNumber来保存当前的loopCounter值?

for (var loopCounter = result.StartingPoint; loopCounter <= result.HighestPageCount; loopCounter++)
{
  ...
  var newDiv = document.createElement('div');
  ...
  //trying to remove the reference to loopCounter
  var pageNumber = loopCounter;
  newDiv.onclick = 
    function(event) 
    { //Right here ---V
      getResultUsingUrl(result.PagerPreLink + "&pageNumber=" + pageNumber);
    };

  ...
}

感谢下面的几个答案:

function createClickMethod(loopCounter, link)
{
    var pageNumber = loopCounter;

    return function(event) { getResultUsingUrl(link + "&pageNumber=" + pageNumber); };
}

我可以这样打电话:

newDiv.onclick = createClickMethod(loopCounter, result.PagerPreLink);

或者,如果我想使用jQuery ...建议如下:

jQuery(newDiv).click
(
    createClickMethod(loopCounter, result.PagerPreLink)
);

5 个答案:

答案 0 :(得分:9)

像其他人一样,这是一个范围问题。如果不使用JS库,您可以执行以下操作:

newDiv.onclick = (function() {
    var num = loopCounter;
    return function(evt) {
        console.log( num );
    }
})();

你只需要在值周围创建另一个闭包。

答案 1 :(得分:5)

您每次都不会创建新的pageNumber。你只有一个。 JavaScript中的范围不超出功能范围。你在一个函数中声明的任何“var” - 在循环中或循环外 - 的工作方式与你在函数顶部声明的完全相同。

http://javascript.crockford.com/code.html

答案 2 :(得分:2)

Javascript闭包存储对其变量的引用,因此所有onclick处理程序都使用相同的变量。

您需要在中间函数中捕获变量,如下所示:

function buildClickHandler(pageNumber) {
    return function(event)  {    //Create and return a new function
        getResultUsingUrl(result.PagerPreLink + "&pageNumber=" + pageNumber);
    }
}

然后,使用该函数创建onclick处理程序,如下所示:

for (var loopCounter = result.StartingPoint; loopCounter <= result.HighestPageCount; loopCounter++) { 
    //...

    var newDiv = document.createElement('div');

    newDiv.onclick = buildClickHandler(loopCounter);
}

每次调用buildClickHandler都会创建一个单独的闭包,它有自己的变量。


顺便说一句,考虑使用jQuery进行DOM操作;它比原始DOM API容易得多。

在您的示例中,您可以编写

$('<div />').click(buildClickHandler(loopCounter));

答案 3 :(得分:1)

是result.StartingPoint真的是一种原始类型,例如实际的数字类型?如果没有,那么可能正在发生的是你正在获得对该对象的引用,然后字符串连接正在为你做类型强制。试试这个:

var pageNumber = new Number(loopCounter); // force coercion

答案 4 :(得分:0)

onclick闭包不会保持其范围,因此无法访问结果。

查看dojo.hitch以获得简单而强大的解决方案,以便您可以控制其范围。