I was working today at a front-end Javascript project. I will try to keep the description of the problem and the solution as short as possible. I had to add click handlers to the links on a page that redirect the user to other pages, so I had 2 Javascript array arrayOfRedirectLinks and pageLinkElements:
var arrayOfRedirectLinks, pageLinkElements;
Initially I wrote the addEventHandlers function like this:
var addEventHandlers = function() { var i, link; for( var i in arrayOfRedirectLinks) { link = arrayOfRedirectLinks[i]; pageLinkElements[i].addEventListener( click , function(e) { e.preventDefault(); window.location = link; }); } }
I thought that this solution will do the job until... well until I opened the browser, clicked several links and noticed that all of them redirected me to the same link( the last link in the arrayOfRedirectLinks).
Finally I found that my problem was similar to the one posted here http://stackoverflow.com/questions/14177757/javascript-multiple-dynamic-addeventlistener-created-in-for-loop-passing-param http://stackoverflow.com/questions/14177757/javascript-multiple-dynamic-addeventlistener-created-in-for-loop-passing-param
And indeed both the first and the second solution posted there worked for me
var addEventHandlers = function() { var i, link; for( var i in arrayOfRedirectLinks) { (function(link){ link = arrayOfRedirectLinks[i]; pageLinkElements[i].addEventListener( click , function(e) { e.preventDefault(); window.location = link; }); }(link)); } }
and
var passLink = function(link) { return function(e) { e.preventDefault(); window.location = link; }; }; var addEventHandlers = function() { var i, link; for( var i in arrayOfRedirectLinks) { link = arrayOfRedirectLinks[i]; pageLinkElements[i].addEventListener( click ,passLink(link)); } }
Now this seems to work but I don t understand why it works. I came with the following explanation and I would like if someone can confirm if it s correct:
1) When I declare a function in Javascript, it gets the references to the variables in the scope of the function where it was declared. ( i.e. my event handler gets a reference to the link variable in the addEventHandlers function)
2) Because the handler gets a reference to the variable link. When I reassign a value to the link variable, the value that will be used when the click handler gets triggered will also change. So the link variable from the event handler is not simply copy with of the link with a different memory address and same value as when the function handler was added, but they both share the same memory address and therefore the same value.
3) Because of the reasons described at 2), the all the click handlers will use the redirect to the same link, the last link in the array arrayOfRedirectLinks because that s the last value that will get assigned to the link variable at the end of the for loop.
4) But when I pass the link variable as a parameter to another function, a new scope it s created and the link inside that scope actually shares only it s initial value with the value of the link parameter passed to the function. The references of the 2 link variables are different.
5) Because of 4), when I pass the link to the click handler, it will take the reference to the link variable in the Immediately Invoked Function Expression who itself doesn t share the same address with the link in the addEventHandlers function. Therefore each link from the event handler functions will be isolated from the others and will keep the value of the arrayOfRedirectLinks[i]
Is this correct?