JavaScript

JavaScript Closure Explained

Normally JavaScript functions can’t remember things. They’re just processes that eat inputs and poop outputs. In, out, gone. No trace left in them. If you were to ask them to personally keep count of the number of times they’ve executed, they would stare back at you with blank, sad eyes.

While closure, simply put, is a JavaScript function that carries its own persistent, private variables [1][2].

That sounds cool. Where do I sign up for one of those variables? Jack, our JavaScript function asks.

function jack() {
  console.log("how do i personally keep count of how many times i've executed?")
}

Since JavaScript scope at function levels, and all functions have access to the scope “above” them [3], when functions are defined inside of another function, the inner functions have access to everything in the parent function.

And the magical part is: functions can see whatever variables are visible at the point where they were declared [4]. Even after the outer function returns; or after the outer function gets destroyed.

function giveBirthToJack() {
  var birthPlaceVar = 0;

  return function jack() {
    return ++birthPlaceVar;
  }
}

If we execute giveBirthToJack, we get Jack version 2.0. Now, Jack can keep a record of something. The whole purpose of the outer function is to produce a function that can keep its own updatable variables, like state of a class. And our function with a remembering superpower, is called closure.

Since birthPlaceVar is not a global variable, the only way to access it is to call the closure function, which essentially makes the variable private.

There are multiple ways to grab hold of an inner function, in order to create a closure. You could:

  • return the closure function
  • assign the closure to another object/array
  • pass the closure as a parameter to another function
  • it’s called closure as long as it’s accessing variables outside of the scope where it’s executed.

Now that we have a vague idea of what closure is all about, lets step into the fun.

WHAT IF?

See if you can work out the output of the code. Select to check with the answer.

// what if i create two jacks?

function giveBirthToJack() {
  var counter = 0;
  return jack = function() {
    return ++counter;
  }
}

var jack = giveBirthToJack();
var jackJunior = giveBirthToJack();
console.log(jack(), jackJunior());

Answer: 1, 2

Explanation: A closure is not an instance of a class. It is the only copy, and can be accessed by reference. Likewise, the counter they referred to is the same variables. jack === jackJunior.

// what about what happened after Jack is defined?

function giveBirthToJack() {
  var counter = 0;
  var jack = function() {
    return ++counter;
  }
  counter++;
  return jack;
}

var jack = giveBirthToJack();
console.log(jack());

Answer: 2

Explanation: Those private variables are referred to only when jack is called. By then, everything inside giveBirthToJack has already finished executing. As a result, closures can’t keep a copy of their old values. They can only refer to the latest value, at the end of their parent function.

// a challenge
var logNum = [];

function parent() {
  for (var i = 0; i < 3; i++) {
    logNum[i] = function child() {
      console.log(i);
    }
  }
}

parent();
console.log(logNum[0](), logNum[1](), logNum[2]());

Answer: 3, 3, 3

Explanation: It’s a tricky thing to use for loop with closures. Remember the “only refer to the latest value”? By the time the any one of the logNum function is called, “i” is already 3. Instead, select the code below to see how the assignment can be forced:

// within the for loop, to force feed the number i in:
logNum[i] = (function (x) {
  return function child() {
    console.log(x);
  }
})(i);

WHY USE CLOSURE?

1. Private data support.

JavaScript isn’t a pure Object Oriented language, and therefore doesn’t support private data. With closures, we can essentially make data private [5].

2. To use callbacks easily.

Generally, when you call functions with a callback in mind, the callback function needs access to the data that’s available at the beginning, and closures make this easy. For instance, with HTTP requests [6]:

function sendRequest() {
  var requestID = "123";
  Ext.Ajax.request({
    url:'/myUrl'
    success: function(response) {
      alert("Request " + requestID + " returned");
    }
  });
}

Because of JavaScript’s closures, we can access “requestID” inside the success function, which achieves the sharing of data between request and response functions. While without closures, you’d need to pass in requestID as an argument, or create an object containing requestID and the function.

Standard