Javascript - Closure

javascript

Articles

// JavaScript  Closure:

Any function defined inside another function can access the outer function’s 
passed-in arguments and variables. The name of this relationship is closure.

The closure has access to variables in three scopes:
1. Variables declared in their own scope
2. Variables declared in a parent function
3. Variables declared in the global namespace

We can use closure to create private variables, create a curry, or specify the 
context object for a function.

// Closure and event handling
Using IIFE can be a mouthful at times.  Using a function that returns a function
can help:

function createHandler(i) {
   return function() {
      console.log('You clicked element #' + i);
   }
}
var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', createHandler(i));
}

In the above code, in each iteration of the for loop, the value of i is passed
to the createHandler function, and because the handler function being returned
from the createHandler function has a closure relationship with the createHandler
function, it can see the value of i.  In reality, we should use event delegation
instead of directly binding the event handler to each element like this, because
each time we bind and event handler to an element directly like this, it consume
some memory.

Named Closures.  Feel free to give your closures a name.  It will produce a better 
stack traces.  For example:

req.on('end', function onEnd() {...});

In the above code, instead of simply using an anonymous function such as:

req.on('end', function() {...});

we use the name onEnd.

Some best practices regarding closures.  Use closures, but do not nest them.  
Otherwise our code will become a mess.  Compare:

setTimeout(function() {
  client.connect(afterConnect);
}, 1000);

function afterConnect() { ... }

with the following code:

setTimeout(function() {
  client.connect(function() { ... });
},1000);

The first version is probably easier to understand and probably contain less bugs 
compared to the second version for a more complex case.  As we work, we 
should strive to break down complex methods into simpler methods that are 
easier to understand.

What is a closure?

The idea behind a closure: Any function defined inside another function can access the outer function’s passed-in arguments and variables. The name of this relationship is closure.

A closure is a Function instance coupled with the local variables from its environment that are necessary for its execution. When a function is declared, it has the ability to reference any variables that are in its scope at the point of declaration. These variables are carried along with the function even after the point of declaration has gone out of scope.

What can we use a closure for?

We can use closure to hide variables, or in other words, create private variables.

How can we create a simple closure?

function makeCounter() {
  // The variable `i` is only accessible inside `makeCounter`.
  var i = 0;

  return function() {
    console.log( ++i );
  };
}

var counter = makeCounter();
counter(); // logs: 1
counter(); // logs: 2

var counter2 = makeCounter();
counter2(); // logs: 1
counter2(); // logs: 2

// Note that `counter` and `counter2` each have their own scoped `i`.
// Each time that we invoke makeCounter(), the variable i is created, and it
// is that instance that is visible to the new function that get returned.

In the above code, the returned function (or the inner function) is automatically have access to variables defined in the outer function (i), but outside the outer function, the variable i is not defined. Inside the outer function, and the inner function, the variable i is not isolated with global object.

In the above code, the makeCounter() function returns a function. The returned function has access to the variables that are defined inside the makeCounter() function.

Here is another example of a closure:

$(function(){
  var local = 1;
  window.setInterval(function(){
    local++
  },300);
});

In the above code, we define a ready handler that fires after the DOM is loaded. This ready handler is a function, and inside this function, we declare a local variable named 'local' and assign it a numeric value of 1. And then, we defined another inner function, the one that we use with setInterval. This inner function has access to the variables that are declared inside the ready handler function.

You might have noticed that the closure, as with all closures in JavaScript was created implicitly without the need for explicit syntax as is required in some other languages that support closures. This is a double-edged sword that make it easy to create closure (whether you intend to or not) but can make them difficult to spot. Unintended closures can have unintended consequences. For example, circular references can lead to memory leaks. A classic example of this is the creation of DOM elements that refer back to closure variables, preventing those variables from being reclaimed.

Here is another example of using a closure to create private and public variables and methods:

myObject = (function(){
    var netWorth;  // private variable
    var cry = function() { ... }; // private method
    return {
        birthYear: 1973, // public properties
        birthDay: 17,
        birthMonth: 2,
        getAge: function() { return blah; } // public method
    }
})();

How can we use closure to hide variables?

In JavaScript, every function, when invoked, creates a new execution context. Because variables and functions defined within a function may only be accessed inside, but not outside, that context, invoking a function provides a very easy way to create privacy.

// Because this function returns another function that has access to the
// "private" var i, the returned function is, effectively, "privileged."

function makeCounter() {
  // The variable `i` is only accessible inside `makeCounter`.
  var i = 0;

  return function() {
    console.log( ++i );
  };
}

// Note that `counter` and `counter2` each have their own scoped `i`.

var counter = makeCounter();
counter(); // logs: 1
counter(); // logs: 2

var counter2 = makeCounter();
counter2(); // logs: 1
counter2(); // logs: 2

i; // ReferenceError: i is not defined (it only exists inside makeCounter)

In the above code, the returned function (or the inner function) is automatically have access to variables defined in the outer function (i), but outside the outer function, the variable i is not defined. Inside the outer function, and the inner function, the variable i is not isolated with global object.

How can we correctly install handler (in a loop)?

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', function() {
      console.log('You clicked element #' + i);
   });
}

Given the above code, what will be printed on the console if a user clicks the first and the fourth button in the list and why?

The code prints two times You clicked element #NODES_LENGTH where NODES_LENGTH is the number of the nodes retrieved. The reason is that after the for loop is completed, the variable i is equal to nodes.length. The issue can be fixed in several different ways. The first solution involves the use of an IIFE (Immediately-Invoked Function Expression) to create another closure:

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', (function(i) {
      return function() {
         console.log('You clicked element #' + i);
      }
   })(i));
}

In the above code, the second arguments to addEventListener is not the typical function that we normally use. The second parameter to addEventListener is actually wrapped inside a () followed by (i). When JavaScript see this pattern, the first function is executed immediately. The first function actually returns the second function. This second function, because it is inside the first function, it has access to the variables that was accessible to the first function when the first function was executed.

Another possible solution doesn’t involve the use of an IIFE and moves the function outside the loop. This approach is implemented by the following code:

function handlerWrapper(i) {
   return function() {
      console.log('You clicked element #' + i);
   }
}

var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {
   nodes[i].addEventListener('click', handlerWrapper(i));
}

This above approach is essentially the same as the previous approach. We are using a function that returns another function.

Another approach:

var elems = document.getElementsByTagName( 'a' );

for ( var i = 0; i < elems.length; i++ ) {

  (function( lockedInIndex ){

    elems[ lockedInIndex ].addEventListener( 'click', function(e){
      e.preventDefault();
      alert( 'I am link #' + lockedInIndex );
    }, 'false' );

  })( i );

}

In the above code, elems can be a global variable or a closure (if the above code was inside another function). Notice that in the above code, the inner function is not returned by the outer function. The inner function is directly used as the second argument to addEventListener. The above approach works, because inside the IIFE, the value of `i` is locked in as `lockedInIndex`. After the loop has finished executing, even though the value of `i` is the total number of elements, inside the IIFE the value of `lockedInIndex` is whatever the value passed into it (`i`) was when the function expression was invoked, so when a link is clicked, the correct value is alerted.

How can we simulate block-scope?

JavaScript does not have block-scope, but you can fake it (not sure how useful this code is yet):

(function () {
    var x = ...;
})();
function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6);
y(7);

The name of the makeAdder() function should give it away: it creates new 'adder' functions, which when called with one argument add it to the argument that they were created with.

What's happening here is pretty much the same as was happening with the inner functions earlier on: a function defined inside another function has access to the outer function's variables. The only difference here is that the outer function has returned, and hence common sense would seem to dictate that its local variables no longer exist. But they do still exist - otherwise the adder functions would not work. What's more, there are two different copies of makeAdder's local variables - one in which a is 5, and one in which a is 20.

Here's what's actually happening. Whenever javascript executes a function, a 'scope' object is created to hold the local variables created within that function. It is initialized with any variables passed in as function parameters. This is similar to the global object that all global variables and functions live in, but with a couple of important differences: first, a brand new scope object is created everytime a function starts executing, and secondly, unlike the global object (which in browsers is accessible as window) these scope objects cannot be directly accessed from your javascript code. There is no mechanism for iterating over the properties of the current scope object.

So when makeAdder is called, a scope object is created with one property: a, which is the argument passed to the makeAdder function. makeAdder then returns a newly created function. Normally JavaScript's garbage collector would cleanup the scope object created for makeAdder at this point, but the returned function maintains a reference back to that scope object. As a result, the scope object will not be garbage collected until there are no more references to the function object that makeAdder returned.

Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.

A closure is the combination of a function and the scope object in which it was created. Closures let you save state - as such, they can often be used in place of objects.

Closures are means through which inner functions can refer to the variables present in their outer enclosing function after their parent functions have already terminated.

In some functional programming language, there's a concept of currying. Currying is a way to, essentially, pre-fill in a number of arguments to a function, creating a new, simpler function:

// A function that generates a new function for adding numbers
function addGenerator( num ) {
  // Return a simple function for adding two numbers
  // with the first number borrowed from the generator
  // Look closely, we are using closure on num
  return function( toAdd ) {
    return num + toAdd;
  }
}
var addFive = addGenerator(5);
alert( addFive(4) == 9);

New JavaScript developers tend to accidentally leave a lot of variables sitting in the global scope. This is generally considered to be bad practice, as those extra variables could quietly interfere with other libraries, causing confusing problem to occur. Using a self-executing anonymous function, you can essentially hide all normal global variables from being seen by other code:

(function(){
})();

Closures allow us to reference variables that exist within the parent function. However, it does not provide the value of the variable at the time it is created. It provides that last value of the variable within the parent function. The most common issue under which you'll see this occur is during a for loop. There is one variable being used as the iterator. Inside the for loop, new functions are being created that utilize the closure to reference the iterator again. The problem is that by the time the new closured function are called, they will reference the last value of the iterator (i.e., the last position in an array), not the value that you would expect.

// An example of using anonymous functions to induce the scope
// needed to create multiple closures inside for loop
var obj = document.getElementById("main");
// An array of items to bind to
var items = [ "click", "keypress" ];
// Iterate through each of the items
for ( var i = 0; i < items.length; i++ ) {
  // Use a self-executed anonymous function to induce scope
  (function(){
    // Remember the value within this scope
    var item = items[i];
    // Bind a function to the element
    obj[ "on" + item ] = function() {
      // item refers to a parent variable that has been successfully
      // scoped within the context of this for loop
      alert( "Thanks for your " + item);
    };
  })();
}

How can we access the context of the outer function from inside an inner function?

The context of the outer function is never included as part of the closure. If we need to have access to the context of the outer function, assign the this context to a local variable inside the outer function:

var outer = this;
$('*').each(function(){
  // ...
});

The 'local' variable is assigned a reference to the outer's function context, becomes part of the closure and can be accessed inside the callback function.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License