Search code examples
javascriptiife

Why do these two functions have different results?(Sorry, I don't know how to describe them)


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


Solution

  • 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.