Closures: Line by Line explanation of "Javascript: Good Parts" example? - javascript

I'm reading "Javascript: The Good Parts" and am totally baffled by what's really going on here. A more detailed and/or simplified explanation would be greatly appreciated.
// BAD EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the wrong way.
// When you click on a node, an alert box is supposed to display the ordinal of the node.
// But it always displays the number of nodes instead.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
}
}
};
// END BAD EXAMPLE
The add_the_handlers function was intended to give each handler a unique number (i). It fails because the handler functions are bound to the variable i, not the value of the variable i at the time the function was made:
// BETTER EXAMPLE
// Make a function that assigns event handler functions to an array of nodes the right way.
// When you click on a node, an alert box will display the ordinal of the node.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(i);
};
}(i);
}
};
Now, instead of assigning a function to onclick, we define a function and immediately invoke it, passing in i. That function will return an event handler function that is bound to the value of i that was passed in, not to the i defined in add_the_handlers. That returned function is assigned to onclick.

I think this is a very common source of confusion for newcomers to JavaScript. First I would suggest checking out the following Mozilla Dev article for brief introduction on the topic of closures and lexical scoping:
Mozilla Dev Center: Working with Closures
Let's start with the bad one:
var add_the_handlers = function (nodes) {
// Variable i is declared in the local scope of the add_the_handlers()
// function.
var i;
// Nothing special here. A normal for loop.
for (i = 0; i < nodes.length; i += 1) {
// Now we are going to assign an anonymous function to the onclick property.
nodes[i].onclick = function (e) {
// The problem here is that this anonymous function has become a closure. It
// will be sharing the same local variable environment as the add_the_handlers()
// function. Therefore when the callback is called, the i variable will contain
// the last value it had when add_the_handlers() last returned.
alert(i);
}
}
// The for loop ends, and i === nodes.length. The add_the_handlers() maintains
// the value of i even after it returns. This is why when the callback
// function is invoked, it will always alert the value of nodes.length.
};
We can tackle this problem with more closures, as Crockford suggested in the "good example". A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. In JavaScript, the environment of the closure consists of any local variables that were in-scope at the time that the closure was created:
// Now we are creating an anonymous closure that creates its own local
// environment. I renamed the parameter variable x to make it more clear.
nodes[i].onclick = function (x) {
// Variable x will be initialized when this function is called.
// Return the event callback function.
return function (e) {
// We use the local variable from the closure environment, and not the
// one held in the scope of the outer function add_the_handlers().
alert(x);
};
}(i); // We invoke the function immediately to initialize its internal
// environment that will be captured in the closure, and to receive
// the callback function which we need to assign to the onclick.
Rather than having the callbacks all sharing a single environment, the closure function creates a new environment for each one. We could also have used a function factory to create a closure, as in the following example:
function makeOnClickCallback (x) {
return function (e) {
alert(x);
};
}
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = makeOnClickCallback(i);
}

It's all about closures. In the first example, "i" will be equal to "nodes.length" for every click event handler, because it uses "i" from the loop which creates the event handlers. By the time the event handler is called, the loop will have ended, so "i" will be equal to "nodes.length".
In the second example, "i" is a parameter (so a local variable). The event handlers will use the value of the local variable "i" (the parameter).

In both examples any node that's passed has an onclick event handler bound to it (just like <img src="..." onclick="myhandler()"/>, which is bad practice after all).
The difference is that in the bad example every closure (the event handler functions, that is) is referencing the exact same i variable due to their common parent scope.
The good example makes use of an anonymous function that gets executed right away. This anonymous function references the exact same i variable as in the bad example BUT since it is executed and provided with i as its first parameter, i's value is assigned to a local variable called ... eh? ... i, exactely - thus overwriting the one defined in the parent's scope.
Let's rewrite the good example to make it all clear:
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (newvar) {
return function (e) {
alert(nevar);
};
}(i);
}
};
Here we replaced i in the returned event handler function with newvar and it still works, because newvar is just what you'd expect - a new variable inherited from the anonymous function's scope.
Good luck figuring it out.

It has to do with closure.
When you do the thing in the bad example,
when you click each node, you will get the latest i value (i.e. you have 3 nodes, no matter what node you click you will get 2). since your alert(i) is bound to a reference of variable i and not the value of i at the moment it was bound in the event handler.
Doing it the better example way, you bound it to what i as at the moment that it was iterated on, so clicking on node 1 will give you 0, node 2 will give you 1 and node 3 will give you 2.
basically, you are evaluating what i is immediately when it is called at the line }(i) and it got passed to parameter e which now hold the value of what i is at that moment in time.
Btw... I think there is a typo there in the better example part... it should be alert(e) instead of alert(i).

Related

javascript closure for_loop [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I have read a number of explanations about closures and closures inside loops. I have a hard time understanding the concept. I have this code: Is there a way to reduce the code as much as possible so the concept of closure can be made clearer. I am having a hard time understanding the part in which the i is inside two parenthesis. Thanks
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function (num) {
return function () {
alert(num);
};
}(i);
document.body.appendChild(link);
}
}
window.onload = addLinks;
WARNING: Long(ish) Answer
This is copied directly from an article I wrote in an internal company wiki:
Question: How to properly use closures in loops?
Quick answer: Use a function factory.
for (var i=0; i<10; i++) {
document.getElementById(i).onclick = (function(x){
return function(){
alert(x);
}
})(i);
}
or the more easily readable version:
function generateMyHandler (x) {
return function(){
alert(x);
}
}
for (var i=0; i<10; i++) {
document.getElementById(i).onclick = generateMyHandler(i);
}
This often confuse people who are new to javascript or functional programming. It is a result of misunderstanding what closures are.
A closure does not merely pass the value of a variable or even a reference to the variable. A closure captures the variable itself! The following bit of code illustrates this:
var message = 'Hello!';
document.getElementById('foo').onclick = function(){alert(message)};
message = 'Goodbye!';
Clicking the element 'foo' will generate an alert box with the message: "Goodbye!". Because of this, using a simple closure in a loop will end up with all closures sharing the same variable and that variable will contain the last value assigned to it in the loop. For example:
for (var i=0; i<10; i++) {
document.getElementById('something'+i).onclick = function(){alert(i)};
}
All elements when clicked will generate an alert box with the number 10. In fact, if we now do i="hello"; all elements will now generate a "hello" alert! The variable i is shared across ten functions PLUS the current function/scope/context. Think of it as a sort of private global variable that only the functions involved can see.
What we want is an instance of that variable or at least a simple reference to the variable instead of the variable itself. Fortunately javascript already has a mechanism for passing a reference (for objects) or value (for strings and numbers): function arguments!
When a function is called in javascript the arguments to that function is passed by reference if it is an object or by value if it is a string or number. This is enough to break variable sharing in closures.
So:
for (var i=0; i<10; i++) {
document.getElementById(i).onclick =
(function(x){ /* we use this function expression simply as a factory
to return the function we really want to use: */
/* we want to return a function reference
so we write a function expression*/
return function(){
alert(x); /* x here refers to the argument of the factory function
captured by the 'inner' closure */
}
/* The brace operators (..) evaluates an expression, in this case this
function expression which yields a function reference. */
})(i) /* The function reference generated is then immediately called()
where the variable i is passed */
}
I've been programming in JavaScript for a long time, and "closure in a loop" is a very broad topic. I assume you are talking about the practice of using (function(param) { return function(){ ... }; })(param); inside of a for loop in order to preserve the "current value" of the loop when that inner function later executes...
The code:
for(var i=0; i<4; i++) {
setTimeout(
// argument #1 to setTimeout is a function.
// this "outer function" is immediately executed, with `i` as its parameter
(function(x) {
// the "outer function" returns an "inner function" which now has x=i at the
// time the "outer function" was called
return function() {
console.log("i=="+i+", x=="+x);
};
})(i) // execute the "closure" immediately, x=i, returns a "callback" function
// finishing up arguments to setTimeout
, i*100);
}
Output:
i==4, x==0
i==4, x==1
i==4, x==2
i==4, x==3
As you can see by the output, all of the inner callback functions all point to the same i, however, since each had its own 'closure', the value of x is actually stored as whatever i was at the time of the outer function's execution.
Commonly when you see this pattern, you would use the same variable name as the parameter and the argument to the outer function: (function(i){ })(i) for instance. Any code inside that function (even if executed later, like a callback function) is going to refer to i at the time you called the "outer function".
Well, the "problem" with closures in such a case is, that any access to i would reference the same variable. That is because of ECMA-/Javascripts function scope or lexical scope.
So to avoid that every call to alert(i); would display a 5 (because after the loop finished i === 5), you need to create a new function which invokes itself at runtime.
To achieve this, you need to create a new function, plus you need the extra paranthesis at the end, to invoke the outer function immediately, so link.onclick has now the returned function as reference.
A closure is a construct in which you reference a variable outside the scope in which it's defined. You usually talk about closures in the context of a function.
var helloFunction;
var finished = false;
while (!finished) {
var message = 'Hello, World!';
helloFunction = function() {
alert(message);
}
finished = true;
}
helloFunction();
Here, I define the variable message, and define a function that references message. When I define the function to use message, I am creating a closure. This means helloFunction holds a reference to message, so that I can continue to use message, even outside of the scope (the loop body) where message is defined.
Addendum
The (i) in parenthesis is a function call. What's happening is:
You define some function(num) {}. This is called an anonymous function, because it's defined inline and doesn't have a name.
function(num) takes an integer argument, and returns a reference to another function, which is defined as alert(num)
The outer anonymous function is immediately called, with the argument i. So num=i. The result of this call is a function which will do alert(i).
The end result is more or less equivalent to: link.onclick = function() { alert(i); };
To answer the last part of your questions. The two parenthesis invoke the function as any other functions. Why you do it here is that you want to keep what the variable "i" is just at that time. So what it does is, invoke the function, the i is sent as a argument "num". Since it's invoke it will remember the value nume in variable links own scoop.
If you did't to this all link click would result in an alert saying "5"
John Resig, founder of jQuery, has a really nice online presentation explaining this. http://ejohn.org/apps/learn/
..fredrik

why javascript use call by reference , sometimes :D [duplicate]

This code is supposed to pop up an alert with the number of the image when you click it:
for(var i=0; i<10; i++) {
$("#img" + i).click(
function () { alert(i); }
);
}
You can see it not working at http://jsfiddle.net/upFaJ/. I know that this is because all of the click-handler closures are referring to the same object i, so every single handler pops up "10" when it's triggered.
However, when I do this, it works fine:
for(var i=0; i<10; i++) {
(function (i2) {
$("#img" + i2).click(
function () { alert(i2); }
);
})(i);
}
You can see it working at http://jsfiddle.net/v4sSD/.
Why does it work? There's still only one i object in memory, right? Objects are always passed by reference, not copied, so the self-executing function call should make no difference. The output of the two code snippets should be identical. So why is the i object being copied 10 times? Why does it work?
I think it's interesting that this version doesn't work:
for(var i=0; i<10; i++) {
(function () {
$("#img" + i).click(
function () { alert(i); }
);
})();
}
It seems that the passing of the object as a function parameter makes all the difference.
EDIT: OK, so the previous example can be explained by primitives (i) being passed by value to the function call. But what about this example, which uses real objects?
for(var i=0; i<5; i++) {
var toggler = $("<img/>", { "src": "http://www.famfamfam.com/lab/icons/silk/icons/cross.png" });
toggler.click(function () { toggler.attr("src", "http://www.famfamfam.com/lab/icons/silk/icons/tick.png"); });
$("#container").append(toggler);
}
Not working: http://jsfiddle.net/Zpwku/
for(var i=0; i<5; i++) {
var toggler = $("<img/>", { "src": "http://www.famfamfam.com/lab/icons/silk/icons/cross.png" });
(function (t) {
t.click(function () { t.attr("src", "http://www.famfamfam.com/lab/icons/silk/icons/tick.png"); });
$("#container").append(t);
})(toggler);
}
Working: http://jsfiddle.net/YLSn6/
Most of the answers are correct in that passing an object as a function parameter breaks a closure and thus allow us to assign things to functions from within a loop. But I'd like to point out why this is the case, and it's not just a special case for closures.
You see, the way javascript passes parameters to functions is a bit different form other languages. Firstly, it seems to have two ways of doing it depending on weather it's a primitive value or an object. For primitive values it seems to pass by value and for objects it seems to pass by reference.
How javascript passes function arguments
Actually, the real explanation of what javascript does explains both situations, as well as why it breaks closures, using just a single mechanism.
What javascript does is actually it passes parameters by copy of reference. That is to say, it creates another reference to the parameter and passes that new reference into the function.
Pass by value?
Assume that all variables in javascript are references. In other languages, when we say a variable is a reference, we expect it to behave like this:
var i = 1;
function increment (n) { n = n+1 };
increment(i); // we would expect i to be 2 if i is a reference
But in javascript, it's not the case:
console.log(i); // i is still 1
That's a classic pass by value isn't it?
Pass by reference?
But wait, for objects it's a different story:
var o = {a:1,b:2}
function foo (x) {
x.c = 3;
}
foo(o);
If parameters were passed by value we'd expect the o object to be unchanged but:
console.log(o); // outputs {a:1,b:2,c:3}
That's classic pass by reference there. So we have two behaviors depending on weather we're passing a primitive type or an object.
Wait, what?
But wait a second, check this out:
var o = {a:1,b:2,c:3}
function bar (x) {
x = {a:2,b:4,c:6}
}
bar(o);
Now see what happens:
console.log(o); // outputs {a:1,b:2,c:3}
What! That's not passing by reference! The values are unchanged!
Which is why I call it pass by copy of reference. If we think about it this way, everything makes sense. We don't need to think of primitives as having special behavior when passed into a function because objects behave the same way. If we try to modify the object the variable points to then it works like pass by reference but if we try to modify the reference itself then it works like pass by value.
This also explains why closures are broken by passing a variable as a function parameter. Because the function call will create another reference that is not bound by the closure like the original variable.
Epilogue: I lied
One more thing before we end this. I said before that this unifies the behavior of primitive types and objects. Actually no, primitive types are still different:
var i = 1;
function bat (n) { n.hello = 'world' };
bat(i);
console.log(i.hello); // undefined, i is unchanged
I give up. There's no making sense of this. It's just the way it is.
It's because you are calling a function, passing it a value.
for (var i = 0; i < 10; i++) {
alert(i);
}
You expect this to alert different values, right? Because you are passing the current value of i to alert.
function attachClick(val) {
$("#img" + val).click(
function () { alert(val); }
);
}
With this function, you'd expect it to alert whatever val was passed into it, right? That also works when calling it in a loop:
for (var i = 0; i < 10; i++) {
attachClick(i);
}
This:
for (var i = 0; i < 10; i++) {
(function (val) {
$("#img" + val).click(
function () { alert(val); }
);
})(i);
}
is just an inline declaration of the above. You are declaring an anonymous function with the same characteristics as attachClick above and you call it immediately. The act of passing a value through a function parameter breaks any references to the i variable.
upvoted deceze's answer, but thought I'd try a simpler explanation. The reason the closure works is that variables in javascript are function scoped. The closure creates a new scope, and by passing the value of i in as a parameter, you are defining a local variable i in the new scope. without the closure, all of the click handlers you define are in the same scope, using the same i. the reason that your last code snippet doesn't work is because there is no local i, so all click handlers are looking to the nearest parent context with i defined.
I think the other thing that might be confusing you is this comment
Objects are always passed by reference, not copied, so the self-executing function call should make no difference.
this is true for objects, but not primitive values (numbers, for example). This is why a new local i can be defined. To demonstrate, if you did something weird like wrapping the value of i in an array, the closure would not work, because arrays are passed by reference.
// doesn't work
for(var i=[0]; i[0]<10; i[0]++) {
(function (i2) {
$("#img" + i2[0]).click(
function () { alert(i2[0]); }
);
})(i);
}
In the first example, there is only one value of i and it's the one used in the for loop. This, all event handlers will show the value of i when the for loop ends, not the desired value.
In the second example, the value of i at the time the event handler is installed is copied to the i2 function argument and there is a separate copy of that for each invocation of the function and thus for each event handler.
So, this:
(function (i2) {
$("#img" + i2).click(
function () { alert(i2); }
);
})(i);
Creates a new variable i2 that has it's own value for each separate invocation of the function. Because of closures in javascript, each separate copy of i2 is preserved for each separate event handler - thus solving your problem.
In the third example, no new copy of i is made (they all refer to the same i from the for loop) so it works the same as the first example.
Code 1 and Code 3 didn't work because i is a variable and values are changed in each loop. At the end of loop 10 will be assigned to i.
For more clear, take a look at this example,
for(var i=0; i<10; i++) {
}
alert(i)
http://jsfiddle.net/muthkum/t4Ur5/
You can see I put a alert after the loop and it will show show alert box with value 10.
This is what happening to Code 1 and Code 3.
Run the next example:
for(var i=0; i<10; i++) {
$("#img" + i).click(
function () { alert(i); }
);
}
i++;
You'll see that now, 11 is being alerted.
Therefore, you need to avoid the reference to i, by sending it as a function parameter, by it's value. You have already found the solution.
One thing that the other answers didn't mention is why this example that I gave in the question doesn't work:
for(var i=0; i<5; i++) {
var toggler = $("<img/>", { "src": "http://www.famfamfam.com/lab/icons/silk/icons/cross.png" });
toggler.click(function () { toggler.attr("src", "http://www.famfamfam.com/lab/icons/silk/icons/tick.png"); });
$("#container").append(toggler);
}
Coming back to the question months later with a better understanding of JavaScript, the reason it doesn't work can be understood as follows:
The var toggler declaration is hoisted to the top of the function call. All references to toggler are to the same actual identifier.
The closure referenced in the anonymous function is the same (not a shallow copy) of the one containing toggler, which is being updated for each iteration of the loop.
#2 is quite surprising. This alerts "5" for example:
var o;
setTimeout(function () { o = {value: 5}; }, 100);
setTimeout(function () { alert(o.value) }, 1000);

Explanation needed : Cannot understand javascript returning a function

I am more of a C++/Java programmer and fairly new to Javascript. I have been reading Javascript the good parts book.In the chapter on Functions, the author cites and example of attaching an event listener to nodes in the DOM by doing the following
// When you click on a node, an alert box will display the ordinal of the node.
1 var add_the_handlers = function (nodes) {
2 var i;
3 for (i = 0; i < nodes.length; i += 1) {
4 nodes[i].onclick = function (i) {
5 return function (e) {
6 alert(e);
7 };
8 }(i);
9
10 };
The aim of the above function is to add an onclick event handler to all of the nodes in the DOM such that when anyone of the nodes is clicked it alerts the number assigned to it or its ordinal.
I am not able to understand lines 5 through 8. I understand that the function (the onclick = function(i)...) is immediately called with i as its argument. But how is this 'i' being passed to the function that is being returned ? How is 'e' getting the value of 'i' that is later being alerted?
I tried playing around with it and ran the following code in my browser
window.onclick = function(i){
return function(e){
console.log("Inner function called");
alert(e);
}
}(4);
I expected an alert window with the number 4 in it. Instead the alert window shows [object MouseEvent].
I would really appreciate if someone explained this to me.
Thanks
It's a mistake in the book. They were trying to demonstrate the awful (performance-wise) pattern of using an otherwise unnecessary function scope to allow an inline function to closure around a variable in an outer scope, which, because it is not referenced anywhere else, becomes a kind of private variable referenced only by the inline function. The code would do its job if the i variable was indeed used as the argument to the alert() call:
var add_the_handlers = function(nodes) {
for (var i = 0; i < nodes.length; ++i) {
nodes[i].onclick = function(i) {
return function() {
alert(i);
};
}(i);
} // end for
};
add_the_handlers(document.getElementsByTagName('div'));
http://jsfiddle.net/pzht9mLu/
In the book's code, instead of closuring around the function parameter i in the outer scope, the inline function that becomes the onclick handler doesn't closure around anything. Instead, the e variable that is used as the argument in the alert() call binds to the function parameter e of the inline function (that's why no closuring happens; a closure only happens when a variable reference inside a function scope fails to bind to any local inside the scope, and instead binds to a variable in an outer scope). Because the function ends up serving as an event handler, its parameter e is set equal to the Event object that initiated the callback (if and when it happens), and that's why you see that in the alert message.
What you should realize is that in lines 5-9 (where's number 7 btw?:)) a new function is created, which will be bound as the event listener function of the onclick.
See line 9:
}(i);
This means that the above function is immediately invoked, passing in i as its function parameter, and then it returns a new function.
Should you, for example, use the value of i in this inner function, it is captured in a closure, so the onclick function will have access to it, even though it is invoked from an entirely different scope.
I tried playing around with it and ran the following code in my
browser
window.onclick = function(i){
return function(e){
console.log("Inner function called");
alert(e);
} }(4);
I expected an alert window with the number 4 in it. Instead the alert window shows [object MouseEvent].
The argument i is never used. The alert produces e, which is the argument to the onclick event handler. Which is a MouseEvent object.
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (i) {
return function (e) {
alert(e);
};
}(i);
};
The aim of the above function is to add an onclick event handler to
all of the nodes in the DOM such that when anyone of the nodes is
clicked it alerts the number assigned to it or its ordinal.
I am not able to understand lines 5 through 8. I understand that the
function (the onclick = function(i)...) is immediately called with i
as its argument. But how is this 'i' being passed to the function that
is being returned ? How is 'e' getting the value of 'i' that is later
being alerted?
i Isn't passed to the second function, and will never be shown by your current code. What you're doing now is effectively no different than this:
nodes[i].onclick = function (e) { alert(e); };
If you want to produce an alert with the correct value of i in it, you'd simply use your original code but alert i instead of e.

Javascript: Creating Functions in a For Loop

Recently, I found myself needing to create an array of functions. The functions use values from an XML document, and I am running through the appropriate nodes with a for loop. However, upon doing this, I found that only the last node of the XML sheet (corresponding to the last run of the for loop) was ever used by all of the functions in the array.
The following is an example that showcases this:
var numArr = [];
var funArr = [];
for(var i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = function(){ return i; };
}
window.alert("Num: " + numArr[5] + "\nFun: " + funArr[5]());
The output is Num: 5 and Fun: 10.
Upon research, I found a a segment of code that works, but I am struggling to understand precisely why it works. I reproduced it here using my example:
var funArr2 = [];
for(var i = 0; i < 10; ++i)
funArr2[funArr2.length] = (function(i){ return function(){ return i;}})(i);
window.alert("Fun 2: " + funArr2[5]());
I know it has to do with scoping, but at first glance it does not seem like it would perform any differently from my naive approach. I am somewhat of a beginner in Javascript, so if I may ask, why is it that using this function-returning-a-function technique bypasses the scoping issue? Also, why is the (i) included on the end?
Thank you very much in advance.
The second method is a little clearer if you use a parameter name that does not mask the loop variable name:
funArr[funArr.length] = (function(val) { return function(){ return val; }})(i);
The problem with your current code is that each function is a closure and they all reference the same variable i. When each function is run, it returns the value of i at the time the function is run (which will be one more than the limit value for the loop).
A clearer way would be to write a separate function that returns the closure that you want:
var numArr = [];
var funArr = [];
for(var i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = getFun(i);
}
function getFun(val) {
return function() { return val; };
}
Note that this is doing basically the same thing as the first line of code in my answer: calling a function that returns a function and passing the value of i as a parameter. It's main advantage is clarity.
EDIT: Now that EcmaScript 6 is supported almost everywhere (sorry, IE users), you can get by with a simpler approach—use the let keyword instead of var for the loop variable:
var numArr = [];
var funArr = [];
for(let i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = function(){ return i; };
}
With that little change, each funArr element is a closure bound do a different i object on each loop iteration. For more info on let, see this Mozilla Hacks post from 2015. (If you're targeting environments that don't support let, stick with what I wrote earlier, or run this last through a transpiler before using.
Let's investigate what the code does a little closer and assign imaginary function names:
(function outer(i) {
return function inner() {
return i;
}
})(i);
Here, outer receives an argument i. JavaScript employs function scoping, meaning that each variable exists only within the function it is defined in. i here is defined in outer, and therefore exists in outer (and any scopes enclosed within).
inner contains a reference to the variable i. (Note that it does not redefine i as a parameter or with the var keyword!) JavaScript's scoping rules state that such a reference should be tied to the first enclosing scope, which here is the scope of outer. Therefore, i within inner refers to the same i that was within outer.
Finally, after defining the function outer, we immediately call it, passing it the value i (which is a separate variable, defined in the outermost scope). The value i is enclosed within outer, and its value cannot now be changed by any code within the outermost scope. Thus, when the outermost i is incremented in the for loop, the i within outer keeps the same value.
Remembering that we've actually created a number of anonymous functions, each with its own scope and argument values, it is hopefully clear how it is that each of these anonymous functions retains its own value for i.
Finally, for completeness, let's examine what happened with the original code:
for(var i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = function(){ return i; };
}
Here, we can see the anonymous function contains a reference to the outermost i. As that value changes, it will be reflected within the anonymous function, which does not retain its own copy of the value in any form. Thus, since i == 10 in the outermost scope at the time that we go and call all of these functions we've created, each function will return the value 10.
I recommend picking up a book like JavaScript: The Definitive Guide to gain a deeper understanding of JavaScript in general so you can avoid common pitfalls like this.
This answer also provides a decent explanation on closures specifically:
How do JavaScript closures work?
When you invoke
function() { return i; }
the function is actually doing a variable look-up on the parent call-object (scope), which is where i is defined. In this case, i is defined as 10, and so every single one of those functions will return 10. The reason this works
(function(i){ return function(){ return i;}})(i);
is that by invoking an anonymous function immediately, a new call-object is created in which the current i is defined. So when you invoke the nested function, that function refers to the call-object of the anonymous function (which defines whatever value you passed to it when it was invoked), not the scope in which i was originally defined (which is still 10).

Javascript closure

I read the () at the end of the closure will execute it immediately. So, what is the difference between these two. I saw the first usage in some code.
thanks.
for (var a=selectsomeobj(),i=0,len=a.length;i<len;++i){
(function(val){
anotherFn(val);
})(a[i]);
}
for (var a=selectsomeobj(),i=0,len=a.length;i<len;++i){
anotherFn(a[i]);
}
In this example there are no differences. In both cases, anotherFn gets executed immediately.
However, an immediate function is often used when a function is created in a loop.
Consider this example (more or less pseudo code):
for(var i from 1..10) {
elements[i].onclick = function() {
alert(values[i]);
}
}
As JavaScript has only function scope, no block scope, all the event handlers share the same i, which will have the value 10 after the loop finished. So every handler will try to alert values[10].
By using an immediate function, a new scope is introduced which "captures" the current value of the loop variable:
for(var i from 1..10) {
(function(index) {
elements[i].onclick = function() {
alert(values[index]);
}
}(i));
}
As this is sometimes hard to read, creating a standalone function which returns another function is often better:
function getHandler(value) {
return function(){alert(value);};
}
for(var i from 1..10) {
elements[i].onclick = getHandler(values[i]);
}
In both instances in your example the values do identical operations. There are other examples out there where if you're not careful to use the first method (with the self-executing anonymous function), the value of i will increment and not be passed correctly to your function.
Here's a guide, scroll down to the creating closures in loops: a common mistake section to see the problem:
https://developer.mozilla.org/en/JavaScript/Guide/Closures
the first defines a self-invoking function (which in turn executes a function), the second just executes the function. In both cases the argument passed to the is a[i].

Categories

Resources