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
link
variable in theaddEventHandlers
function)Because the handler gets a reference to the variable
link
. When I reassign a value to thelink
variable, the value that will be used when the click handler gets triggered will also change. So thelink
variable from the event handler is not simply copy with of thelink
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.Because of the reasons described at 2), the all the click handlers will use the redirect to the same
link
, the lastlink
in the arrayarrayOfRedirectLinks
because that's the last value that will get assigned to thelink
variable at the end of thefor
loop.But when I pass the
link
variable as a parameter to another function, a new scope it's created and thelink
inside that scope actually shares only it's initial value with the value of thelink
parameter passed to the function. The references of the 2link
variables are different.Because of 4), when I pass the
link
to the click handler, it will take the reference to thelink
variable in the Immediately Invoked Function Expression who itself doesn't share the same address with thelink
in theaddEventHandlers
function. Therefore eachlink
from the event handler functions will be isolated from the others and will keep the value of thearrayOfRedirectLinks[i]
Is this correct?