Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Your <code>setTimeout</code> argument function is declared to take a single parameter, <code>i</code>. When <code>setTimeout</code> calls the function with no arguments, as it does, the parameter is thus set to <code>undefined</code>.</p> <p>This would seem to be be slightly better, as it no longer shadows the outer <code>i</code> variable you were originally trying to reference...</p> <pre><code>setTimeout(function() { console.log(i); }, 2000) </code></pre> <p>...but if you run it, you'll find it prints <code>10</code> 5 times, because every function you create is referencing the same <code>i</code> variable, whose value will be <code>10</code> when the loop exit condition becomes <code>true</code> and it terminates.</p> <p>Creating a <em>closure</em> which holds the value of <code>i</code> as it was during the loop in which each <code>setTimout</code> argument function was created will do the trick:</p> <pre><code>setTimeout((function(i) { return function() { console.log(i); } })(i), 2000) </code></pre> <p>Renaming the argument to the <a href="http://benalman.com/news/2010/11/immediately-invoked-function-expression/">Immediately-Invoked Function Expression</a> we just used might help make things clearer:</p> <pre><code>setTimeout((function(loopIndex) { return function() { console.log(loopIndex); } })(i), 2000) </code></pre> <p>We're:</p> <ul> <li>Creating a function which takes a single argument and returns another function.</li> <li><em>Immediately</em> calling the "outer" function, passing it the current value of <code>i</code> (which is not an object, so is effectively passed by value).</li> <li>The "outer" function returns the "inner" function, which is passed as the argument to <code>setTimeout</code>.</li> </ul> <p>This works because:</p> <ol> <li><p>Creating a function in JavaScript creates a new <em>scope</em> to hold the function's argument variables and any other variables declared within it using the <code>var</code> keyword. Think of this like an invisible object with properties corresponding to the variable names. </p></li> <li><p>All functions hold a reference to the scope in which they were defined, as part of their <em>scope chain</em>. They still have access to this scope even if it's no longer "active" (e.g. when the function it was created for returns). The "inner" function was created in a scope which contained a <code>loopIndex</code> variable, set to the value of <code>i</code> at the time the IIFE was called. So when you try to reference a variable named <code>loopIndex</code> from inside the inner function, it first checks its own scope (and doesn't find a <code>loopIndex</code> there) <em>then</em> starts walking up its scope chain - first, it checks the scope in which it was defined, which <em>does</em> contain a <code>loopIndex</code> variable, the value of which is passed to <code>console.log()</code>.</p></li> </ol> <p>That's all a closure is - a function which has access to the scope in which it was defined, even if the function the scope was created for has finished executing.</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. 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.
    3. VO
      singulars
      1. This table or related slice is empty.
    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