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 Javascript multiple dynamic addEventListener created in for loop - passing parameters not working
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:
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
linkvariable in theaddEventHandlersfunction)Because the handler gets a reference to the variable
link. When I reassign a value to thelinkvariable, the value that will be used when the click handler gets triggered will also change. So thelinkvariable from the event handler is not simply copy with of thelinkwith 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.Because of the reasons described at 2), the all the click handlers will use the redirect to the same
link, the lastlinkin the arrayarrayOfRedirectLinksbecause that's the last value that will get assigned to thelinkvariable at the end of theforloop.But when I pass the
linkvariable as a parameter to another function, a new scope it's created and thelinkinside that scope actually shares only it's initial value with the value of thelinkparameter passed to the function. The references of the 2linkvariables are different.Because of 4), when I pass the
linkto the click handler, it will take the reference to thelinkvariable in the Immediately Invoked Function Expression who itself doesn't share the same address with thelinkin theaddEventHandlersfunction. Therefore eachlinkfrom the event handler functions will be isolated from the others and will keep the value of thearrayOfRedirectLinks[i]
Is this correct?