In summary I have the following code:
let incrementer = (function() {
let counter = 0;
let IncreaseCounter = () => {
return counter += 5;
}
return IncreaseCounter;
})();
console.log(incrementer); // function body () => {}
console.log(incrementer()) // 5
console.log(incrementer()) // 10
console.log(incrementer()) // 15
incrementer doesn't work even though i had it wrapped in an IIFE.
Is there any way to print out incrementer as a variable to be incremented each time, without the invocation ()?
Is there any other way in Javascript to achieve such goal other than that closure approach?
Related
Why in Example 1 and Example 2 return different results?
A conter variable(example 1) instance still has access from the global scope.
Example 1:
const increment = (()=> {
let counter = 0;
//console.log(counter);
const credits = (num) => console.log(`I have ${num} credit(s).`);
return () => { counter++; credits(counter); }
})();
increment();//I have 1 credit(s).
increment();//I have 2 credit(s).
Example 2:
function a() {
let counter = 0;
const credits = (num) => console.log(`I have ${num} credit(s).`);
return () => { counter++; credits(counter); }
}
a()();//I have 1 credit(s).
a()();//I have 1 credit(s).
Thanks.
The let counter line initializes a counter variable. This will occur whenever that line runs.
In the first example, you run that line once when you invoke the IIFE with })() at the end, and the function returned by the IIFE references that one counter variable you initialized.
In the second example, you run that line every time the a function runs - a new counter variable is created every time you do a(). So if you do a()(), you create one counter variable, increment it in the returned function, log it, and then discard it (since the counter can't be referenced by anything anymore). Calling a()() and then a()() results in two separate counter variables, both of which you increment by 1 and log.
If you wanted to log 2 by tweaking the second example, assign the returned function to a variable before calling it, then call that returned function twice (instead of calling a twice).
function a() {
let counter = 0;
const credits = (num) => console.log(`I have ${num} credit(s).`);
return () => { counter++; credits(counter); }
}
const fn = a();
fn();//I have 1 credit(s).
fn();//I have 2 credit(s).
This question already has answers here:
Why do javascript variables in closure functions not reset to a default when called multiple times?
(2 answers)
Closed 2 years ago.
Simple JS logic question here.. In the below code, why does add() only set counter to 0 once? I feel like every time the function is called it should reset it to zero.
var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
add(); // 1
add(); // 2
Thanks!
You're misunderstanding the code. The function add() does not contain the code var counter = 0.
Here's a rewrite of the exact same code that makes it more clear:
var add;
// Note: THIS function is NOT add()
(function () {
var counter = 0;
// THIS function is add()
add = function () {counter += 1; return counter}
})();
add(); // 1
add(); // 2
The code above does exactly the same thing as your original code except for how add was assigned. In your code it was assigned via a return value but in the above I simply assigned it directly as a global variable to make it more clear which function is add().
Another way to look at it that is more like your original code is to explicitly name the two functions:
var function1 = function () {
var counter = 0;
// The returned function is what will be assigned to add()
return function () {counter += 1; return counter}
}; // Do not call it yet since calling it was what was confusing you
var add = function1();
add(); // 1
add(); // 2
Hello I have a code here:
/* example counter app */
const incrCounter = () => {
let count = 0;
return () => {
return ++count;
}
}
/* now use the counter */
incrCounter()();
incrCounter()();
alert(incrCounter()()); // expect 3 but gets 1
I expect to get an alert that says 3 but I get 1 instead.
I got a live demo here:
https://jsfiddle.net/gunitinug/L9nrt085/1/
Thanks.
Every time incrCounter is called, you get a function in return which closes over a count variable that was just created. If you call incrCounter 3 times, you get 3 separate count variables, in different closures.
Call it once to get the function that closes over a single binding of count, then call that function 3 times, so that that one binding is incremented 3 times:
const makeCounter = () => {
let count = 0;
return () => {
return ++count;
}
}
const counter = makeCounter();
counter();
counter();
console.log(counter());
Giving the function more accurate names will make things more understandable as well - like above, you could call the function-that-returns-a-function makeCounter, and call the returned function counter.
The count variable should be outside the function to retain its value
/* example counter app */
let count = 0;
const incrCounter = () => {
return () => {
return ++count;
}
}
/* now use the counter */
incrCounter()();
incrCounter()();
alert(incrCounter()());
Thanks for all your input guys.
On closer inspection I could do this:
/* example counter app */
const incrCounter = (() => {
let count = 0;
return () => {
return ++count;
}
})();
/* now use the counter */
incrCounter();
incrCounter();
alert(incrCounter());
More flexible version in my opinion.
const makeCounter = (count = 0) => () => ++count
const counter = makeCounter(5);
console.log(counter()); // 6
console.log(counter()); // 7
console.log(counter()); // 8
console.log(counter()); // 9
consider the following code
var fs = [];
for(var i=0;i<10;i++){
fs.push(i => console.log(i));
}
fs.forEach( f => f());
If the function is changed to:
for(let i=0;i<10;i++){
fs.push(function(){
console.log(i)
});
}
It will print the 1,2,3,4,5,6,7,8,9 expected output.
I am not understanding why. Can someone help.
let and var makes no difference for your code with regard to why you're getting 10x undefined.
What does make a difference is that your arrow function is defined taking a parameter i (overwriting the outer index i) whereas in your 2nd example it is not.
const fs = [];
for (var i = 0; i < 10; i++) {
fs.push(() => console.log(i));
}
fs.forEach(f => f());
If you add that parameter to your second example, you also get 10x undefined.
const fs = [];
for (let i = 0; i < 10; i++) {
fs.push(function(i) {
console.log(i)
});
}
fs.forEach(f => f());
The difference between var and let in your code is more subtle:
const fs = [];
for (var i = 0; i < 10; i++) {
fs.push(() => console.log(i));
}
fs.forEach(f => f());
const fs = [];
for (let i = 0; i < 10; i++) {
fs.push(() => console.log(i));
}
fs.forEach(f => f());
With let every function in the array has a locally scoped closure i, whereas with var at execution time i is 10 (because there is only a single variable i that is closured in each function).
There are 2 different issues which need to be covered in some detail. Lets focus on the first case where the main issue is that you define an ES6 arrow function and call it later with no parameters:
i => console.log(i) when converted to ES5 anonymous function notation is:
function(i){ console.log(i) }
So in i => console.log(i) what you have is a short hand ES6 definition of an anonymous function (also known as ES6 arrow function notation) which accepts a parameter i.
The end result is that console.log(i) is trying to print an i which is undefined since it is not passed to that arrow function at execution time.
You re pushing a function definition which later you are executing without passing into it a parameter which it needs to actually output it in the console.
var fs = [];
for(var i=0; i<10; i++){
// You are pushing to the array the below anonymous function definition
fs.push(
// You are creating an anonymous function which accepts i and console.logs it
i => console.log(i)
);
}
fs.forEach(
// You are calling the "pushed" above function definition with NO parameter i
f => f()
);
Now lets explore why and how the 2nd code example works and how var/let play a big role on console output:
let fs = []
// You define i in the for-loop block score
for(var i=0; i<10; i++){
fs.push(
// You push an annonymous function definition wich has a reference of i in the same block scope
// However i is already here 10 since the loop is already done and it takes the last value of i
function(){ console.log(i) }
);
}
fs.forEach(
// You call f which has a reference inside to the i from the for loop
f => f()
);
So in this case i when you use var i the i since it does not retain its lexical block scope ends up being updated to 10 before the console.log gets called.
Lets try this now with let:
let fs = []
// You define i via LET in the for-loop block score
for(let i=0; i<10; i++){
fs.push(
// You push an annonymous function definition wich has a reference of i in the same block scope
// i retains its lexical scope in for loops
function(){ console.log(i) }
);
}
fs.forEach(
// You call f which has a reference inside to the i from the for loop
f => f()
);
So little bit more on let:
let allows you to declare variables that are limited in scope to the
block, statement, or expression on which it is used. This is unlike
the var keyword, which defines a variable globally, or locally to an
entire function regardless of block scope.
In your first example, the i in fs.push(i => console.log(i)); is the parameter of the arrow function. this is effectively equivalent to fs.push(function(i){ return console.log(i); });
This parameter has the same name as the iterator of the loop. In the scope of the function you are pushing, the parameter i takes priority over the outside variable. If you want to capture the iterator you should not name it the same as the parameter, like so:
fs.push(() => console.log(i));
Now you will see there is a difference between var and let in this situation. Your output will be 10,10,10,10,10,10,10,10,10,10. This is because of the scoping difference between var and let. When declared with var, the loop iterator will be the same object throughout the duration of the loop. All of the functions are capturing the same object. The final value after the loop ends (i++ happens and then the conditional check happens) is 10, so they all print 10. With let, the iterator is a new object each iteration of the loop, so each function captures a new object which holds the current count of the loop.
Why does the variable counter keep increasing when it re-initializes itself back to 0 in the self-invoking function?
var add = (function () {
var counter = 0;
return function () {
return counter += 1;
}
})();
add();
add();
add();
// the counter is still 3 when this line of code exists
// var counter = 0;
So when add() function gets invoked, a function runs first with initializing counter = 0 and returning another function that returns the incremental value of counter. Why is this the case when there's var counter = 0; ?
source: https://www.w3schools.com/js/js_function_closures.asp
edit: November 16th, 2017
Okay so it makes a lot more sense now from both of the answers given on this page. For extra clarification, I will add my own reasoning to give it a better visualization of why this happens.
//first call of add()
(function(){ // a self-invoking function
var counter = 0; // executes once with the self-invoking function
return function() { return counter += 1; } //explained below
});
//since the self-invoke function ran already, add() will begin to run the returned function:
add = function() { return counter += 1; };
add(); ----> counter += 1; -----> add.counter = 1;
//counter acts like this.counter, so it's a part of add()
//counter is now at 1
//second call of add();
//add has now officially been **transformed** to the new function:
add = function() {
return counter += 1;
};
//while add.counter still **exists** and remains in the self-invoke
//function. Do we call this **limbo variable** ? Don't know.
//add.counter is at 2
//third call of add();
function() {
return counter += 1;
}
//add.counter is at 3!
Please note that "var add" assigned a self invoking function that returns a function.
Whatever above the return statement is the self invoking function closure. Which means that it is available to the returned function.
So it is in fact only initialized once. And then the return function, which is what the variable "add" now contains, increments the counter whenever it is invoked.
Because the variable add contains the result of the self invoking function. So the value of add is this:
function () {
return counter += 1;
}
The counter variable is only initialized before this function is set to the add variable.