2

I have 2 question

  1. What is the difference between counter1() and counter1()()?
    Isn't counter1 already the function name? Why the second ()?

  2. Why counter2 can memorize the value?

Here is my code:

const counter1 = function(){
  let initValue = 0
  return function(){
    initValue++;
    return initValue
  }
}

const counter2 = (function(){
  let initValue = 0
  return function(){
    initValue++;
    return initValue
  }
})()

console.log(counter1());
console.log(counter1()());
console.log(counter1()());
console.log(counter2());
console.log(counter2());

Here is the output:

enter image description here

greybeard
  • 2,249
  • 8
  • 30
  • 66
Meow
  • 134
  • 1
  • 11
  • this will help you https://stackoverflow.com/a/111111/13647574 – MUHAMMAD ILYAS Jan 10 '21 at 07:09
  • 1
    In simper words, `counter1` is function which will return another function. `counter2` is [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) function which will invoke immediately and returns inner function. – Naren Jan 10 '21 at 07:28

2 Answers2

4

counter1 is a function that returns a function, or what is called a higher-order function.

For the ease of discussion, let innerCounter1 be the name of the return value of counter1. So the following code is equivalent to what you have in your example.

 const counter1 = function(){
   let initValue = 0
   const innerCounter1 = function(){
     initValue++;
     return initValue
   }
   return innerCounter1;
 }

Isn't counter1 already the function name? Why the second ()?

Yes, counter1 is a function, but it also returns a function. By naming the return value innerCounter1, I hope it's clear that when you call counter1(), the value you get is innerCounter1. And when you call innerCounter1(), the value you get is the number initValue. So counter1()() is getting the value of innerCounter1 and calling that inner function in one short expression.

Why counter2 can memorize the value?

When a function is created (innerCounter1 in your example), and the function references value defined outside of the function (initValue in your example), a closure is created, which you can intuitively understand as "memorizing" the variable. Both the functions counter1() and counter2 remembers the value, but the thing to note here is that each time counter1() is called, the local variables (initValue and innerCounter1) are independent. For example:

let counter1A = counter1();
let counter1B = counter1();

counter1A(); // 1
counter1A(); // 2
counter1B(); // 1
counter1B(); // 2

In other words, counter1A and counter1B are remembering a separate initValue variable, so calling one doesn't affect the other.

And this definition of counter2: let counter2 = counter1();, is equivalent to yours above with the anonymous function syntax, so it should be clear that what's happening is exactly the same as counter1A I explained above.

fdermishin
  • 3,519
  • 3
  • 24
  • 45
Maurice Lam
  • 1,577
  • 9
  • 14
0

In JS you can return a function from a function which then can be used anywhere you want, add to that: that returned function can still access the variables where it was defined(can access its lexical scope variables) this feature is called closures.

Please read the comment with code carefully

const counter1 = function () {
    let initValue = 0
    return function () {
        initValue++;
        return initValue
    }
}
/**
 * is the same as
 */
function counter1() {
    let initValue = 0

    /** this function is returned */
    return function () {
        /** 
         * and can access the variable `initValue` at run time because at auth time its scope is inside 
         * the `counter1` scope where the variable is defined in
         * (because inner scope can access outer scope defined in them)
         * 
         */
        initValue++;
        return initValue
    }
}
/**
 * as for using counter1
 * in each time we call the `counter1` we get a reference to the inner anonymous function that has 
 * access to that variable but in each call we have new `initValue` variable that's why 
 * no matter how many times you call `counter1` you keep getting the same result because you have new 
 * `initValue` for each call 
 */





const counter2 = (function () {
    let initValue = 0
    return function () {
        initValue++;
        return initValue
    }
})()
/**
 * this form of defining a function and immediately executing it called IIEF(Immediately invoked function expression)
 * 
 * what this code is executed you have counter2 which is equal to the inner function returned from the outer function expression
 * 
 */

// naming anonymous functions for easing
const counter2 = (function IIFE_counter2() {

    let initValue = 0

    return function counter2_returned_function() {
        initValue++;
        return initValue
    }
})()

/**
 * no counter2 = counter2_returned_function
 *
 * so
 * 1- it can access `initValue` each time it's called
 * 2- for each call of counter2 we are not creating new instance of `IIFE_counter2` instead we just call the inner
 * `counter2_returned_function` which still have the old value of `initValue` and can update it successfully
 */

please read from YDKJS to get more experience at this topic https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch7.md

Louay Al-osh
  • 3,177
  • 15
  • 28