问题
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)
);
回答1:
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.
回答2:
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.com/code.html
回答3:
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));
回答4:
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
回答5:
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.
来源:https://stackoverflow.com/questions/1313064/possible-access-to-modified-closure-issue-how-to-beat