> is 'a local scope for i' the same as 'a closure' ?

No. As the article on closures 
<https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Closures> that 
Adrien linked to states, a closure is a function that refers to variables 
in the environment in which it is created.

So a closure in a loop looks like this:

for (var i = 0; i < 10; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

The inner function is called a closure because it refers to the variable 
"i", which is defined in the outer environment. The important thing to 
remember is that when the closure, the inner function, is created, it isn't 
binding to *the current value *of "i", but rather to the *variable*. The 
current value may be different if the function is executed later, as it is 
in this example, which will execute the 10 instances of the inner function 
after 1 second and all of them will see "i" as having a value of 10 because 
that's the state the loop left "i" in after it finished looping a second 
earlier.

But if you do something like this:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(i) {
  setTimeout(function() {
    console.log(i);
  });
});

Note that there are two functions being created. The inner function is a 
closure because it refers to "i" which is coming from its environment, but 
the outer function is not a closure because the variable "i" is not defined 
in the outside environment, it is defined inside the function (in the 
arguments list). This is the function that gives "i" a local scope. Note 
that variables defined in the arguments list are treated the same as 
variables defined with "var" statements within the function -- they 
"belong" to that function, their scope is the function.

If you still want to use "for" instead of Array.forEach() (or if you want 
to use "for...in" instead of Object.keys()) then you can explicitly bind 
the current value of "i" to the inner function via Function.bind() and it 
will be passed into the function as an argument when the function is 
executed. This is called "currying". It isn't the primary function of bind 
(the primary function is binding the "this" value, but since we don't care 
about that, we pass "null" as the first argument to bind()):

for (var i = 0; i < 10; i++) {
  setTimeout(function(j) {
    console.log(j);
  }.bind(null, i), 1000);
}

We could have named the argument "i" as well, since this variable is scoped 
to the inner function, it will take precedence over the "i" in the outer 
function and would make the "i" in the outer function inaccessible. This 
function is not a closure because it isn't referring to a variable in the 
outside environment (but Function.bind() isn't magic, it probably uses a 
closure internally).

-- Peter Rust
Cornerstone Systems


On Sunday, January 18, 2015 at 7:25:50 PM UTC-8, [email protected] wrote:
>
> Ah yes! Thank you serapath, I figured it out from what you said (and I 
> really was being stupid!) To clarify for anyone reading:
>
> the loop kicks off the callbacks, but they don't actually get executed 
> until the loop has finished. By that point i is 3, and because it is 
> effectively globally scoped, this is the value that is used by *all* of the 
> callbacks in the loop.
> The solution is to create a local scope for i.
>
> Thanks for the feedback guys, and sorry again for the dumb question.
>
> By the way, is 'a local scope for i' the same as 'a closure' ? I was under 
> the impression these two things were not the same...?
>
>

-- 
Job board: http://jobs.nodejs.org/
New group rules: 
https://gist.github.com/othiym23/9886289#file-moderation-policy-md
Old group rules: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
--- 
You received this message because you are subscribed to the Google Groups 
"nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/nodejs/14d0e158-1722-4f2e-aef6-ef74f15cb92b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to