Closure inside for loop, what is the inner IIFE for? - javascript

I have been working through this article on closures: Understand Javascript Closures with Ease
The final example deals with a closure inside a for loop.
I understand why an IIFE is used to capture the current value of 'i' as 'j'. What I don't understand about this example is why there is a 2nd, inner IIFE wrapped around the return statement. (My comment is in caps in the code below).
The code seems to work just the same without the inner IIFE. See CodePen here.
Is this inner function required for some reason, or is this just an oversight by the author?
function celebrityIDCreator (theCelebrities) {
var i;
var uniqueID = 100;
for (i = 0; i < theCelebrities.length; i++) {
theCelebrities[i]["id"] = function (j) { // the j parametric variable is the i passed in on invocation of this IIFE
return function () { //<--WHY DOES THIS INNER FUNCTION NEED TO BE HERE?
return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array
} () // BY adding () at the end of this function, we are executing it immediately and returning just the value of uniqueID + j, instead of returning a function.
} (i); // immediately invoke the function passing the i variable as a parameter
}
return theCelebrities;
}
var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0},{name:"Willis", id:0}];
var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
var stalloneID = createIdForActionCelebs [0];
console.log(stalloneID.id); // 100
var cruiseID = createIdForActionCelebs [1];
console.log(cruiseID.id); // 101
var willisID = createIdForActionCelebs[2];
console.log(willisID.id); //102

The inner function, as you observed, has no practical effect. It doesn't make sense to use it.
It appears to be a holdover from the previous example in the article where a function was returned instead of a number.

Related

Variables in a IIFE

I am trying to understand closures in Javascript. I came across this example :
var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
add();
add();
add();
I do not understand why counter value comes to be 3. I can clearly see that counter is being intialized with 0 each time the function is called.
Let's have a look at what gets interpreted in which order.
Step #1:
In var add = (something)(), the first thing to be evaluated is the "something".
Step #2:
Once evaluated as a valid function, there is a reference to it which is not yet stored in a variable and never will because the function is getting executed right away due to the second set of parenthesis.
Step #3:
That function does 2 things:1) it assigns 0 to the counter variable.2) it declares another function: function () {counter += 1; return counter}. The reference to that function is what will be assigned to the add variable.
Step #4:So each times add() is called, what is executed is counter += 1; return counter.
Scope:
The counter variable only exist in the outer and inner functions. The outer function never had its reference stored to a variable because it was immediately called, so it never will be called again. The inner function reference was stored in add and can be called again.
var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
// Notice that add is the "inner" function
console.log(add)
// What is returned by add is the counter value
var firstCall = add();
var secondCall = add();
var thirdCall = add();
console.log(firstCall, secondCall, thirdCall)
// the counter does not exist outside the scope of the inner function
console.log(typeof(counter))
A good reference I can suggest to learn more about how JS is interpreted is Wakata.io... Particularly the CompuThink section for your question.
The function within the parentheses, followed by another pair of parentheses is an IIFE - immediately invoked function expression.
//immediately invoked function expression
(function() {
var counter = 0;
return function() {
counter += 1;
return counter;
}
})();
This is called so because this function gets called immediately after it is defined.
The variable add is not assigned the IIFE. Rather, it gets the result of the invoked function as below.
function() {
counter += 1;
return counter;
}
A closure is the means by which a function has access to the scope in which it is created.
This function has access to counter variable in the IIFE because of closure behaviour. Even though IIFE's life time is already over, the function in add variable has access to it due to closure.
Whenever we are calling add(), it is actually updating the counter in IIFE. All the while, IIFE was never executed again. It ran only once during the initial phase.

Why does moving an async callback outside of a loop change the result?

Consider the following code snippets:
for(var i = 0; i < arr.length; ++i) {
var newObject = new someFunction(arr[i]);
//async callback function
$http.get('someurl').then(
function(data) {
newObject.data = data;
}
);
}
VS
function registerCallbacks(o) {
$http.get('someurl').then(
function(data) {
o.data = data;
}
);
}
for(var i = 0; i < arr.length; ++i) {
var newObject = new someFunction(arr[i]);
registerCallbacks(newObject);
}
The first example will perform the async operation only on the last object in the array, while the second example will work as expected.
I understand that in the first example, the callbacks all refer to the same variable 'newObject', so only one object is acted upon.
But why isn't it like this in the second example as well? Wouldn't 'o' end up referring to the parameter of the last function call?
I'm afraid I've missed something fundamental about how values are passed in javascript and would be grateful if someone could elucidate me on how it works.
Cheers!
In the first example, newObject object may not have the same value by the time asynch callBack is invoked since its scope is still there in its parent method, and the prevailing values of newObject will be used by the inner block.
However, in the second one newObject is passed to another method as o (a new reference) which doesn't have the same variables in scope since it is outside that for loop block.

Closures in javascript, when are they in effect?

I am new to js and I am experimenting with closures. There is something I can't get my head around.
If I write
var uniqueInteger = (function() { // Define and invoke
var counter = 0; // Private state of function below
return function() { return counter++; };
}());
and I repeatedly call the function as uniqueInteger() I obtain 0,1,2,3 and so on. It seems then that counter is not destroyed after the function is called. Where is it stored since it is not a global object?
Now, if I slightly change the code and define uniqueInteger as
var uniqueInteger = (function() { // Define and invoke
var counter = 0; // Private state of function below
return function() { return counter++; };
});
and I repeatedly call uniqueInteger()() the value which I obtain is constantly 0. How is that possible?
Where is it stored since it is not a global object?
In the scope created by the closure.
Now, if I slightly change the code … the value which I obtain is constantly 0. How is that possible?
Because every time you call var counter = 0; in the second chunk of code, you rerun the expression var counter = 0; (you also create a new scope and return a new function which you immediately call because you had ()()).
In the first chunk of code you ran that function once and assigned its return value to uniqueInteger, so the expression that set counter to 0 was only evaluated once.

JavaScript closure and scope chain

Can anyone explain why document.write part always outputs 10?
function creatFunctions() {
var result = new Array();
for (var i = 0; i < 10; i++) {
result[i] = function () {
return i;
}
}
return result;
}
var funcs = creatFunctions();
for (var i = 0; i < funcs.length; i++) {
document.write(funcs[i]() + "<br />");
}
I think the answer to this question is more thorough than the duplicate question, therefore worth keeping this post.
Sure.
In your for loop, you reference i. What you expect to be happening is that each closure gets a snapshot of i at the time the function is created, therefore in the first function it would return 0, then 1, etc.
What's really happening is that each closure is getting a reference to the external variable i, which keeps updating as you update i in the for loop.
So, the first time through the loop, you get a function that returns i, which at this point is 0. The next time you get two functions which return i, which is now 1, etc.
At the end of the loop, i==10, and each function returns i, so they all return 10.
UPDATE TO ADDRESS QUESTION IN COMMENT:
It's a little confusing since you use i in two different contexts. I'll make a very slight change to your code to help illustrate what's going on:
function creatFunctions() {
var result = new Array();
for (var i = 0; i < 10; i++) {
result[i] = function () {
return i;
}
}
return result;
}
var funcs = creatFunctions();
// NOTE: I changed this `i` to `unrelated_variable`
for (var unrelated_variable = 0; unrelated_variable < funcs.length; unrelated_variable++) {
document.write(funcs[unrelated_variable]() + "<br />");
}
... the functions that you create in your creatFunctions() function all return i. Specifically, they return the i that you create in the for loop.
The other variable, which I've renamed to unrelated_variable, has no impact on the value returned from your closure.
result[i] = function () {
return i;
}
... is not the same thing as result[2] = 2. It means result[2] = the_current_value_of_i
Because you reference i as a variable, which, when the function executes, has the value 10. Instead, you could create a copy of i by wrapping in in a function:
(function (i) {
result[i] = function () {
return i;
}
}(i));
The i that you are returning inside the inner function - is the i that was declared inside the for(var i=0...) therefor - it is the same i for all of the functions in result
and by the time you are calling the functions its value is 10 (after the loop ends)
to accomplish what you wanted you should declare another variable inside the scope of the anonymous function
Because reference to "i" is boxed (enclosed) in your closure that you defined.
result[i] = function () {
return i;
}
And it just keeps reference to the "i" var which keeps changing with each iteration.
UPDATE
This is related to the this keyword function scope which defines variable context.
Hence, in JavaScript, there's no such thing as block scope (for, if else, while, ...).
With that in mind, if you assign var funcs to a function definitioncall, the function body (this) will be bound to the global scope var i inside that function will reach the end of the for loop and stays there in memory. In this case i is 10.
Unfortunately for you, since function scope puts every variable to the top, var i will be global as well.
Although I was completely wrong at first, I stand corrected and took the liberty to create the output of your script in this demo.

javascript function closure working

I was going through a javascript book and have encountered the following code on closure
function constFunc() {
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs[i] = function () {
return i;
}
}
return funcs;
}
var f = constFunc();
f[5]();
The output was not 5.
The explanation given was "nested functions do not make private copies of the scope".
i would be grateful if could someone explain the above statement.
When you call constFunc the loop runs and assigns a function to each element of the funcs array. Those functions each return the value of i, which changes on each iteration of the loop from 0 up to 9.
That means that once constFunc has finished executing i will have the value of 9. When you call one of the functions in the array it returns the value of i which as we've just seen is now 9. The value of i is not captured on each iteration of the loop.
You can force it to be captured via a closure in the loop:
for (var i = 0; i < 10; i++) {
(function (i) {
funcs[i] = function () {
return i;
};
}(i));
}
In this case you are effectively creating a new variable with the same value as i on every iteration of the loop. You can see that in action here.
By passing i into a function you end up copying the value of it. So on the first iteration i has the value 0. We pass that value into the new function (the argument i is a different variable to the i declared in the loop initialiser) and then return that value from the array function. This way, each array function is returning a different i, instead of each returning the same i.
WHy did you expect the output of 5? RIght, because at the time the function was created, i was 5. Now, as we can see, the output is not 5 (but, if I didn't miss anything, 9). Now why is that?
The iinside the closure is not evaluated when the function is created, but when it runs. Now this is where the statement you qoted comes into play: there is only ONE i- the one created inside constFunc. All closures work on that one. After constFunc si done working, that i has, obviously, the value of 9 (becaus that's where the loop stops). SO all closures now output 9.
A simpler example:
function outer () {
var i = 0;
function inner () {
return i;
}
i = 99;
}
outer();
inner(); // <- return 99, not 0.
There is one variable called i.
There are 10 functions that return i.
Each one of those functions returns the current value of the single i variable.
Here in this loop:
for(var i=0;i<10;i++)
{
funcs[i]=function(){return i;}
}
due to closure, inside function you are accessing parent level variable of i, which after complete loop will be 10. So after loop when you call these function it will return you value of i which is 10.
You can solve it by passing variable as parameter, as parameter create the new copy of variable which maintain its state even on completion of loop.
var myFunctions= [];
function createMyFunction(i) {
return function() {
console.log("My value: " + i);
};
}
for (var i = 0; i < 3; i++) {
myFunctions[i] = createMyFunction(i);
}

Categories

Resources