3

I’m having a hard time discerning how exactly JavaScript closures work. Please take a look at these two functions and tell how they are different that they produce entirely different results when called multiple times:

Function 1

var add = (function() {
  var counter = 0;
  return function() {
    return counter += 1;
  }
})();
console.log(add()); // result is 1
console.log(add()); // result is 2
console.log(add()); // result is 3

Function 2

function add() {
  var counter = 0;
  function() {
    return counter += 1;
  }
  plus();
}
console.log(add()); // result is 1
console.log(add()); // result is 1
console.log(add()); // result is 1
Spencer Wieczorek
  • 21,229
  • 7
  • 44
  • 54
pedroyanky
  • 323
  • 2
  • 10

6 Answers6

3

In the first example, counter is declared and the function being called when invoking add is essentially:

function (){
    return counter += 1;
}

This is important because counter isn't being redeclared every time add is being called.

In the second example, counter is being redeclared each time add is called.

Moishe Lipsker
  • 2,974
  • 2
  • 21
  • 29
2

In case 1 you are returning a function which has a Closure over the outer IIFE. As a result the returned function is able to store the values of count even after it has been returned (i.e. Closure) and hence gets an updated values everytime you call add()

Your case 2 seems to be incorrect. You don't have the plus function defined. And even if you define it you will get undefined because you are not returning anything from add()

function add() {
  var counter = 0;
  function plus () {
    return counter += 1;
  }
  plus();
}
console.log(add()); // result is 1
console.log(add()); // result is 1
console.log(add()); // result is 1

When you return plus() from it you will get only 1, because you are actually returning the result of executing counter += 1 every time and everytime counter is reset to 0 when you invoke add()

Aditya Singh
  • 15,810
  • 15
  • 45
  • 67
  • true that was an oversight – pedroyanky Jun 29 '16 at 06:38
  • so you are saying that counter in the case 0f function one in not being redeclared every time it is called? how is that possible? cos i learnt somewhere that whenever function is being called, a new execution context is created. what really is the distinctive marker between the two – pedroyanky Jun 29 '16 at 06:41
  • 1
    @pedroyanky: The function that contains `var counter = 0;` is only executed **once**. The inner function (`return function() { ... }`) is what you are calling "every time" you call `add()`. The difference between the example is that the first one does `var add = (function() { ... }())`, while the second one does `var add = function() {};`. The first one executes the outer function *once*, the second one executes the outer function "every time". *"cos i learnt somewhere that whenever function is being called, a new execution context is created."* That's why `counter` is reset in the second case – Felix Kling Jun 29 '16 at 06:42
2

How is this pair of JavaScript functions different?

In each example you are declaring two functions, one nested inside the other.

In the first example, you are calling the outer function once, return the inner function and assigning it to add. That means that calling add will only execute the inner function.

In the second example, add refers to the outer function. Hence calling add will always execute the outer and the inner function.


Maybe you see the difference better if we rewrite the first example slightly (it still produces the same result):

// Example 1
function add() {
  var counter = 0;
  return function plus() {
    return counter += 1;
  }
}

var plus = add();
console.log(plus());
console.log(plus());

Note how add is only called once, which means that var counter = 0; is only executed once, and plus is the function we are actually calling. Because plus was defined inside add, it has access to counter.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
1

You cannot access any variables defined within the enclosure outside that enclosure. That helps you avoid conflicts, like if the same variable name is used by several functions.

0

In the first example, the outer function is run once, which sets up the counter variable to zero. The outer function returns the inner function, and assigns it to the variable add. When you call add(), the inner function runs in the context it was declared in, so it can increment the counter variable.

In the second example, the outer function is declared, with the name add. You run this outer function each time you call add. This outer function is setting the counter to zero every time, then runs the inner plus function, which increments the counter to 1 and returns it.

dtkaias
  • 781
  • 4
  • 14
  • this helps thanks. what i understand now is that the value of the counter is being stored in the variable add. since the anonymous function is being stored in a variable, is it safe to say that whenever the function is been called, the variable add receive an updated version of counter? – pedroyanky Jun 29 '16 at 06:53
  • The counter isn't stored in the variable, it is the function that is stored. Whenever the function runs, it can still access everything it had access to when it was declared, including the `counter` variable, which is still in memory even though the outer function is no longer running. – dtkaias Jun 29 '16 at 06:58
  • yea, i think am really getting a hang of it now. Thanks – pedroyanky Jun 29 '16 at 07:04
0

Here is what exactly happen in the first snippet.

var add = (function() {
  var counter = 0;
  return function() {
    return counter += 1;
  }
})();

In the above statement you are assigning the variable add a function that increases the counter.

Things to notice:

  1. You get this function by executing an enclosure function. (please note what the enclosure function returns)

  2. You execute the enclosure function by placing () right after it.

Now the variable add is a function which just increases the counter. Here the environment is set to make a closure - so inner function always remember the previous value of the counter.

Thus, you see the increased number every time you execute the inner function via add variable.

Charlie
  • 22,886
  • 11
  • 59
  • 90