Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>When you do this (assuming there's a <code>photo = photos[i]</code> there that you left out in your question):</p> <pre><code>img.onclick = function() { window.location = 'pics/user/' + photo.user_id }; </code></pre> <p>The variable <code>photo</code> inside the function refers to the same variable as <code>photo</code> outside 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 only <code>photo</code>.</p> <p>By the time anyone actually clicks on the image and <em>calls</em> the function, the loop has long since terminated, and <code>photo</code> is 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.</p> <p>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 <code>photo</code> in the non-working example above, which is <em>used</em> inside the function but <em>declared</em> outside it) are created fresh on every function invocation. When <code>photo</code> is 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.</p> <p>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:</p> <pre><code>function makeOnclick(somePhoto) { return function() { hotlink(somePhoto); } } </code></pre> <p>And then the loop body could do this:</p> <pre><code>img.onclick = makeOnclick(photo) </code></pre> <p>You're calling <code>makeOnclick</code> and passing it <code>photo</code> as a parameter. The <code>makeOnclick</code> function is declared far away, where it couldn't use <code>photo</code> directly even if you wanted it to; it can't see that variable at all. Instead, all it has is its local parameter <code>somePhoto</code> - which is created as a brand new variable every time you call <code>makeOnclick</code>. It's initialized with the value of <code>photo</code> at the point of the call, but it's just a copy, so when <code>photo</code> changes on the next loop iteration, that particular instance of <code>somePhoto</code> will stay the same. When the next iteration calls <code>makeOnclick</code>, it will create a new instance of <code>somePhoto</code> initialized to the new value of <code>photo</code>, and so on. So even though the inner function that <code>makeOnClick</code> is returning is inheriting the <code>somePhoto</code> var, that var was just created especially for that instance of <code>makeOnClick</code>; every one of those returned functions gets its own private <code>somePhoto</code>.</p> <p>Your working code above is doing exactly the same thing in a slightly different way. Instead of declaring the <code>makeOnclick</code> function 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:</p> <pre><code>img.onclick = (function(x) { blah(x); })(photo); </code></pre> <p>is the same as this:</p> <pre><code>function foo(x) { blah(x); } img.onclick = foo(photo); </code></pre> <p>without having to give the function a name. In JavaScript in general, this:</p> <pre><code>(function (x,y,z) { doSomething(x,y,z); })(a,b,c); </code></pre> <p>is the same as this:</p> <pre><code>function callDoSomething(x,y,z) { doSomething(x,y,z); } callDoSomething(a,b,c); </code></pre> <p>except the function has no name and is not saved anywhere; it goes away right after it's called.</p> <p>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.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload