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.
Related
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.
I have referred to multiple links for this concept but it is little bit tricky to wrap the concept around the head completely.
I was going through and example of it on https://www.w3schools.com/js/js_function_closures.asp
var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
add();
add();
add(); //Counter is 3
But isn't every time this is getting called counter is getting reinitialized to 0?
Can someone use table or something to help me understand every step here?
What add holds is returned function in the IIFE. (https://developer.mozilla.org/en-US/docs/Glossary/IIFE)
function () {counter += 1; return counter}
So calling add doesn't reinitialize counter.
var add = (function() {
var counter = 0;
return function() {
counter += 1;
return counter
}
})();
console.log(add());
console.log(add());
console.log(add());
var addHandler = function() {
var counter = 0;
return function() {
counter += 1;
return counter
}
};
const add = addHandler(); // return inner function
console.log(add());
console.log(add());
console.log(add());
In javascript, functions have their own execution environment.
And the execution environment is created when the function is called and disappears when execution is complete.
In the code above, the value in "add" becomes the new function returned after the IIFE function is executed.
In other words, the execution environment of the IIFE function has already been executed and disappeared.
However, the inner returned function is still looking at the parent function's variable "counter".
Previously, it was said that the environment disappears when the function is called. In this case, the remembering the environment of the parent function is called a'closure'.
IIFE is an immediate function.
Functions are declared and called when necessary in the form of "function name()".
The IIFE above will execute the function right away by declaring the function and wrapping it in "()".
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.
For example I have a variable which should increment every time the function is run. I want the variable to initially be given the value of 0, but then increase by 1 every time the function is called. I do not want to give the variable global scope, however obviously if I declare it within the function it is going to be reset to 0 every time it is called.
Is there a simple and efficient way to to do this in Javascript?
My Javascript:
function myFunction(){
var i=0;
//Body of function
i++;
}
You can set the value on the function object itself, like this
function myFunction() {
myFunction.i = myFunction.i || 0;
myFunction.i++;
}
Alternatively, you can use closure, like this
var myFunction = (function () {
var i = 0;
return function () {
// `myFunction` will be this function only and it increments the
// `i` from the enclosed function.
i++;
}
})();
I have a setInterval function that is initializing a varibale with it's id in a for loop, which results in a number of setInterval functions executing in the for loop. Each of the setInterval functions will be assigned to a variable now my question is, is it possible for one single variable to contain the values of all of the setIntervals id's or only one? If all of the id's can all be contained in a single variable is it possible to clear certain setIntervals via there id that is contained in the variable or will I need to declare a unique variable for each setInterval to be able to do this?
var intervalId;
for(var i = 0; i < 10; i++) {
intervalId = setInterval(function() {}, 100);
}
The values returned from setInterval and setTimeout are numbers, so only one will "fit" in a variable.
You could make an array:
var intervalId = [];
for(var i = 0; i < 10; i++) {
intervalId.push( setInterval(function() { ... }, 100) );
}
Note that there's something important missing from your question, and that's the code in the interval function. Specifically, if that code wants to refer to "i", there's a problem: all of the separate functions will share the same "i" variable (the one declared in the loop header).
To get around that, you could do this:
function makeTimerFunction(i) {
return function() {
// the code
if (whatever) { clearInterval(intervalId[i]); }
// and so on
};
}
var intervalId = [];
for (var i = 0; i < 10; i++)
intervalId.push( setInterval( makeTimerFunction(i), 100 ) );
By using a separate function, you create another scope and can "freeze" each value of "i" in a separate, per-timer variable.
edit — #pst points out correctly that if it is really the case that you do want to refer to the timer id from inside the handler functions, then there's really no need for that "intervalId" array at all - you could just use the wrapper function to isolate the call to setInterval().
function createTimer() {
var timerId = setInterval(function() {
// the code
if (whatever) { clearInterval( timerId ); }
// ...
};
}
for (var i = 0; i < 10; ++i)
createTimer();
That way each timer is set up with it's own private timer ID variable. Of course, if you do need the timer id outside the function, then you need an external cache for the ids.