Ok, I understand that in the code below a closure is created when the parent function counter returns an object with a method called count. But can somebody clarify if I'm understanding the control flow correctly? After the counter function is assigned to variable c the first time the method it is invoked, by c.count(), the output is 1. And each additional time it is called the stored n is incremented and the new value is returned. I understand this is possible through the magic of closure so that by calling this four times I get a new value each time ending with 4 instead of simply getting 1 four times over. But where is the value that n holds each time "hanging out" while it waits for me to call the count method again to increment the most recently created value? What will it take for n to have a clean slate again as 0? If I declare a new variable and assign the function counter to it? Trying to wrap my head around all this and these questions occurred to me. I'm not sure if what I'm asking is obnoxious or painfully obvious-- thank you in advance.
function counter() {
var n = 0;
return {
count: function() { return ++n; },
};
}
var c = counter();
console.log(c.count()); // 1
console.log(c.count()); // 2
console.log(c.count()); // 3
console.log(c.count()); // 4
where is the value that n holds each time "hanging out" while it waits for me to call the count method again to increment the most recently created value?
Variable n, of course, is hold in memory. Its behavior is just like on global scope, but within the counter scope.
What will it take for n to have a clean slate again as 0?
Reset it.
I've rewritten your example in self-executing function style to make it clearer. Hope it helps.
var c = (function counter(){
var n = 0;
return {
count: function() { return ++n; },
//don't use keyword 'var', it will create a new variable instead of reseting n
reset: function() { n = 0},
};
})();
console.log(c.count()); // 1
console.log(c.count()); // 2
console.log(c.count()); // 3
console.log(c.count()); // 4
console.log(c.reset());
console.log(c.count()); // 1
console.log(c.count()); // 2
console.log(c.count()); // 3
console.log(c.count()); // 4
Variables in a closure are not stored on any object available from within JavaScript itself, so it is impossible to reset it unless you add another function for it in the object you return:
function counter() {
var n = 0;
return {
count: function() { return ++n; },
reset: function() { n = 0; }
};
}
Related
This question already has answers here:
Increment value each time when you run function
(8 answers)
Closed last year.
I'm trying to store the value of i into a.
function sequence(i,a) {
i=a;
if (i==1) {
i++;
return strings[i]
}
else {
i=0;
i++;
a=i;
return strings[i]
}
};
strings is an array where I have stored five objects. When I call the function first time it enters else block, and then it enters else block second time as well. Is there a way to make the value of a=1 in the first attempt, and make it inter the if block.
I also tried declaring i=0 outside the function, and using just i++. But everytime the function is called, i becomes 0.
It would be great if we don't require 2 variables at all and are able to store and increment the value of i.
You can use a closure (basically a function that's returned from another one but that keeps track of the variables in its outer scope without making them global.)
// Simple array
const arr = [1, 2, 3, 4, 5];
// A button and a function that returns a new function
// (the closure) as the listener.
// Pass in the array of things to it
const button = document.querySelector('button');
button.addEventListener('click', handleClick(arr), false);
// The function accepts the array of things,
// and initialises the array count
function handleClick(arr, index = 0) {
// And we return a function that acts as the
// listener when the button is clicked. It increments
// the value until it hits the end of the array, and
// then starts again. The benefit of the closure is that
// it keeps a note of `index` so you don't have to
return function () {
console.log(arr[index]);
if (index === arr.length - 1) {
index = 0;
} else {
index++;
}
}
}
<button>Next</button>
This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 5 years ago.
I am trying to understand how javascript function returns function handle and why following code prints '2' instead of '1'
var num = 01;
function processAndIncrement() {
var process = function() {
console.log(num);
}
num++;
return process;
}
var proCall = processAndIncrement();
proCall();
The num variable is independent of the functions in your code. Both functions refer to the same variable, so they both mutate the same data and observe the changes.
So the num++ operation increments num before proCall is ever invoked. When proCall is finally invoked, it sees the incremented state of num, because it has already been incremented.
Here's a step-by-step description of the order of operations (ignoring hoisting). Follow the sequence of numbers.
// 1. create the variable
var num = 01;
// 2. create the processAndIncrement function
function processAndIncrement() {
// 4. Assign a function that logs `num` to the `process` variable
var process = function() {
// 8. log the current value of `num` (which was incremented at step 5)
console.log(num);
}
// 5. increment `num`
num++;
// 6. return the `process` function
return process;
}
// 3. Invoke processAndIncrement, and assign its return value to `proCall`
var proCall = processAndIncrement();
// 7. invoke `proCall` (which is the same as the `process` function)
proCall();
If you wanted the increment to happen when proCall is invoked, then num++ should be moved to be inside the process function.
The Code prints 2 because you increment num which's value is already 1 (01 == 1).
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
Say I have this function:
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
setTimeout( function() {
console.log( fruits[i]);
}, i * 1000);
}
}
printFruits(["Lemon", "Orange", "Mango"])
So this returns undefined 3 times.
I can see on a high level that since variables are stored not by value but by reference inside the closure... the loop is finishing first and by the time the functions are dequeued from maybe the Event Loop... the variable is already at undefined (fruits.length evaluates to 3 which is too high for this array size). But why does this perform strangely... it prints "apple" 3 times.
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
var someConstant = i;
setTimeout( function() {
console.log( fruits[someConstant]);
}, someConstant * 100);
}
}
printFruits(["mango", "banana", "apple"])
Shouldn't someConstant be changing as well with i? Why does it seem to be 2 always?
Also this works:
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
(function() {
var current = i;
setTimeout( function() {
console.log( fruits[current]);
}, current * 1000);
})();
}
}
Why is the IIFE necessary to fix this problem?
2nd Example
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
var someConstant = i;
setTimeout(function() {
console.log(fruits[someConstant]);
}, someConstant * 1000);
}
}
printFruits(["Lemon", "Orange", "Mango"])
This logs thrice Mango. Because everytime the someConstant variable is created and re-initialised to i. Recollect how for loop works. i-value is increasing here till 4, checks the condition 4<3, and terminates. So the matter inside the loop executes only thrice. So the last value of someConstant defined in the printFruits functional scope is 2. So when the inner function executes someConstant, its equal to 2. So we get each time Mango.
3rd example
function printFruits(fruits) {
for (var i = 0; i < fruits.length; i++) {
(function() {
var current = i;
setTimeout(function() {
console.log(fruits[current]);
}, current * 1000);
})();
}
}
printFruits(["Lemon", "Orange", "Mango"])
Here the beauty of closures happening. Here its a self executing function being executed, immediately. So when i = 1, it invokes immediately. Every function has a different scope now. There is a seperate current value defined for each. So later when it executes, it recollects whats the value of 'current' when it was defined inside its scope.
The only difference between these samples is that the for loop increments i to 3 before stopping, while the last value which is assigned to someConstant is 2. Your "working" code is outputting Mango three times (index 2 of the array) instead of undefined (index 3 of the array). The general behaviour is the same.
Yes, you do need an IIFE, or ES6's let keyword instead of var.
The difference is that someConstant never gets incremented after the last iteration. The for() loop sets i = 3, the test i < fruits.length fails, so the loop stops. As a result, someConstant is still set to 2 from the last iteration of the loop. Then all the callbacks run, so they all log fruits[2], which is Mango.
You need the IIFE to get each iteration to save its value of i in the closure.
While learning about javascript closures, I came across this answer https://stackoverflow.com/a/111111/3886155 on stackoverflow.
It's a very good explanation of closures.
But I have some confusion in Example 4 and Example 5.
I just copy entire snippet here:
Example 4:
var gLogNumber, gIncreaseNumber, gSetNumber;
function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;
// Store some references to functions as global variables
gLogNumber = function() { console.log(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
}
setupSomeGlobals();
gIncreaseNumber();
gLogNumber(); // 667
gSetNumber(5);
gLogNumber(); // 5
var oldLog = gLogNumber;
setupSomeGlobals();
gLogNumber(); // 666
oldLog() // 5
After reading some examples I can say that whenever function inside the function executes it can always remember the variables declared inside outer function.
I agree that if these closure variable updated anyway it still refers to the new variable value.
My problem in this example is specially related to var oldLog=gLogNumber;
How it can return old number after call to the setupSomeGlobals();?
because now the var num has reset.So why it is not using this new num value 666?
Now Example 5:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + i;
result.push( function() {console.log(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// Using j only to help prevent confusion -- could use i.
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
Here they have pushed functions into array and executed them after loop finishes.But now reference to the closure variables is the latest one after loop finishes.Why not old one?
In both examples you are just assigning function definition to variable or array index.But first one points to old and second one points to latest.Why?
How it can return old number after call to the setupSomeGlobals()
num is not globally scoped, so the value num is in the context of which reference of gLogNumber is invoked.
After invocation of setupSomeGlobals method again, reference to gLogNumber got changed. try this
console.log(Object.is( gLogNumber, oldLog )); //true
setupSomeGlobals();
console.log(Object.is( gLogNumber, oldLog )); //false
So, oldLog retained old reference and hence old value of num, but gLogNumber got new num.
But now reference to the closure variables is the latest one after
loop finishes.Why not old one?
For this problem, have a look at
JavaScript closure inside loops – simple practical example.
Can someone please explain how this gets 50, and how does the algorithm works. Thanks.
var multipliers = function makeMultipliers (max) {
var result = [];
for (var i = 0; i < max; i++)
result.push (function (x) {return x * i;});
return result;
}
multipliers(10) [2] (5)
???
what’s the value?
50, not 5
can you fix it?
Source: http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-170-software-studio-spring-2013/lecture-notes/MIT6_170S13_35-java-fn-cls.pdf
page 30
It's a scope issue. By the time the last function is called, i is where it was last seen at that scope last which would be 10. You can prevent this with a closure.
function multipliers(max){
var a = [];
for(var i=0; i<max; i++){
(function(i){
a.push(function(x){return x*i});
})(i);
}
return a;
}
In this case, the closure is a self-executing function that scopes off i at each step of the loop. If this did not happen the scope would go to the multipliers function itself. Since the loop has already completed by the time you are calling the function which you pass 5 to, which happens to be at step 2 of the Array that multipliers returns, i has already reached 10. Obviously, 10*5 is 50. When the closure is used is last position is 2 within the scope it is in, giving you the result that is sought. 5*2 = 10.
console.log(multipliers(10)[2](5));
This code creates an array of functions which will incorrectly all end up referring to the final value of i, but which are intended to freeze the value of i during each iteration.
To fix it you simply could add a level of locality to the iteration variable by embedding a new local variable that freezes the value of i within another function. For example, below the existing local variable i is passed into the dummy function as an argument, and the value of i at that instant is frozen into the new local variable i which is independent of the original i and not changed by the subsequent iterations of the original i.
result.push (function (x) {return x * i;})
result.push((function(i) {
return function (x) {return x * i;};
})(i));