This solution works, but I don’t understand what the second return function() does?
for (var i = 0; i < photos.length; i ++) {
img.onclick = (function(photo) {
return function() {
hotLink(photo); //window.location = '/pics/user/' + photo.user_id;
};
})(photos[i]);
Also, why do I have to include the (photos[i]); at the end?
Before, I had this, and the onclick would always link to the last photo[i].
for (var i = 0; i < photos.length; i ++) {
img.onclick = function() {
window.location = 'pics/user/' + photo.user_id
};
}
When you do this (assuming there’s a
photo = photos[i]there that you left out in your question):The variable
photoinside the function refers to the same variable asphotooutside the function. It’s not a snapshot that gets the current value of the variable at the time you define the function; it’s just a reference to the same variable. The surrounding loop changes the value of that variable on every iteration, but it doesn’t create a new variable each time; it’s reusing the same one. So all the functions you generate reference that exact same variable – the one and onlyphoto.By the time anyone actually clicks on the image and calls the function, the loop has long since terminated, and
photois gone from the main program’s scope, but it’s still out there in memory because all those functions still have references to it. And they will find it still pointing to the last item in the list, because that was the last thing assigned to it.So you need to give each onclick function its very own variable that won’t change once the function is created. The way to do that in Javascript, since it doesn’t have block scope, is to call a function and pass the value in as a parameter. Function parameters and variables declared inside a function (as opposed to
photoin the non-working example above, which is used inside the function but declared outside it) are created fresh on every function invocation. Whenphotois declared as a function parameter, each onclick gets its very own copy that nothing else can modify, so it still has the right value when someone finally clicks the image.It might be clearer if it used a static function-generator function; there’s really no reason to do the inline declare-and-call thing. You could declare this once, outside the loop:
And then the loop body could do this:
You’re calling
makeOnclickand passing itphotoas a parameter. ThemakeOnclickfunction is declared far away, where it couldn’t usephotodirectly even if you wanted it to; it can’t see that variable at all. Instead, all it has is its local parametersomePhoto– which is created as a brand new variable every time you callmakeOnclick. It’s initialized with the value ofphotoat the point of the call, but it’s just a copy, so whenphotochanges on the next loop iteration, that particular instance ofsomePhotowill stay the same. When the next iteration callsmakeOnclick, it will create a new instance ofsomePhotoinitialized to the new value ofphoto, and so on. So even though the inner function thatmakeOnClickis returning is inheriting thesomePhotovar, that var was just created especially for that instance ofmakeOnClick; every one of those returned functions gets its own privatesomePhoto.Your working code above is doing exactly the same thing in a slightly different way. Instead of declaring the
makeOnclickfunction once, outside the loop, and calling it a bunch of times, it’s redeclaring it every time through the loop as an anonymous function which it then calls immediately. This code:is the same as this:
without having to give the function a name. In JavaScript in general, this:
is the same as this:
except the function has no name and is not saved anywhere; it goes away right after it’s called.
So declaring the onclick-generator function every time through the loop and calling it immediately all at once is nice and concise, but not terribly efficient.