admin管理员组

文章数量:1278789

For some reason no matter what, the pageNumber ends up being the last value in the loop for the loopCounter. Now I would understand that if I were directly using loopCounter in the closure itself, but I'm not. As you can see from the code below, I am creating a new variable within the closure to take the current value of loopCounter.

Only thing I can figure is (Assuming that javascript treats everything as a reference type) that pageNumber is taking the reference to loopCounter so no matter how many times I create a new pageNumber, it's always pointing at the loopCounter object. Therefore, whatever value loopCounter ends up with will be the value any pageNumber will point to.

How do I get it to not point at loopCounter but create a new pageNumber per iteration that holds the current loopCounter value?

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);
    };

  ...
}

SOLUTION

Thanks to a couple answers below:

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

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

and I can call like:

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

Or if I want to use jQuery... suggested below:

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

For some reason no matter what, the pageNumber ends up being the last value in the loop for the loopCounter. Now I would understand that if I were directly using loopCounter in the closure itself, but I'm not. As you can see from the code below, I am creating a new variable within the closure to take the current value of loopCounter.

Only thing I can figure is (Assuming that javascript treats everything as a reference type) that pageNumber is taking the reference to loopCounter so no matter how many times I create a new pageNumber, it's always pointing at the loopCounter object. Therefore, whatever value loopCounter ends up with will be the value any pageNumber will point to.

How do I get it to not point at loopCounter but create a new pageNumber per iteration that holds the current loopCounter value?

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);
    };

  ...
}

SOLUTION

Thanks to a couple answers below:

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

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

and I can call like:

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

Or if I want to use jQuery... suggested below:

jQuery(newDiv).click
(
    createClickMethod(loopCounter, result.PagerPreLink)
);
Share Improve this question edited Jan 7, 2012 at 17:58 Lightness Races in Orbit 385k77 gold badges666 silver badges1.1k bronze badges asked Aug 21, 2009 at 16:53 Programmin ToolProgrammin Tool 6,53711 gold badges52 silver badges69 bronze badges 2
  • What is result.StartingPoint? – Nathan Taylor Commented Aug 21, 2009 at 16:56
  • Eh a an object returned from a asynchronous method call. – Programmin Tool Commented Aug 21, 2009 at 17:20
Add a ment  | 

5 Answers 5

Reset to default 9

Like everyone else said, it's a scoping problem. Without using a JS library, you can do something like this:

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

You just need to create another closure around the value.

You are not creating a new pageNumber each time. You only have one. Scope in JavaScript does not extend beyond function-scope. Any "var" you declare in a function -- in or out of loops -- works exactly as it would had you declared it right at the top of the function.

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

Javascript closures store references to their variables, so all of your onclick handlers are using the same variable.

You need to capture the variable in an intermediate function, like this:

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

Then, use that function to create onclick handlers, like this:

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

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

    newDiv.onclick = buildClickHandler(loopCounter);
}

Each call to buildClickHandler creates a separate closure that has its own variable.


As an aside, consider using jQuery to do DOM manipulation; it's much easier than raw DOM APIs.

In your example, you could write

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

Is result.StartingPoint really a primitive type, e.g. an actual Number type? If not, then perhaps what's happening is that you are getting a reference to that object and then the string concatenation is doing a type-coercion for you. Try this instead:

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

The onclick closure will not maintain its scope, so it won't be able to access result.

Take a look at dojo.hitch for an easy and powerful solution, so that you can control its scope.

本文标签: javascriptPossible Access To Modified Closure Issue How To BeatStack Overflow