Wednesday, 14 March 2012

How do JavaScript closures work?



First Example

Whenever you see the function keyword within another function, the inner function has access to variables in the outer function.

function foo(x) {
  var tmp = 3;
  function bar(y) {
    alert(x + y + (++tmp));
  }
  bar(10);
}
foo(2)

This will always alert 16, because bar can access the x which was defined as an argument to foo, and it can also access tmp from foo. That is not a closure. A closure is when you return the inner function. The inner function will close-over the variables of foo before leaving.

function foo(x) {
  var tmp = 3;
  return function (y) {
    alert(x + y + (++tmp));
  }
}
var bar = foo(2); // bar is now a closure.
bar(10);

The above function will also alert 16, because bar can still refer to x and tmp, even though it is no longer directly inside the scope. However, since tmp is still hanging around inside bar's closure, it is also being incremented. It will be incremented each time you call bar. (Not for your 6 year old: It is possible to create more than one closure function, either by returning a list of them or by setting them to global variables. All of these will refer to the same x and the same tmp, they don't make their own copies.) Edit: And now to explain the part that isn't obvious. Here the number x is a literal number. As with other literals in JavaScript, when foo is called, the number x is copied into foo as its argument x. On the other hand, JavaScript always uses references when dealing with Objects. If say, you called foo with an Object, the closure it returns will reference that original Object!

function foo(x) {
  var tmp = 3;
  return function (y) {
    alert(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    alert(x.memb);
  }
}
var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

As expected, each call to bar(10) will increment x.memb. What might not be expected, is that x is simply referring to the same object as the age variable! After a couple of calls to bar, age.memb will be 2!

Second Example

I'm a big fan of analogy and metaphor when explaining difficult concepts... so let me try my hand with a story... Once upon a time: There was a princess...
function princess() {
She lived in a wonderful world full of adventures. She met her Prince Charming, road around her world on a unicorn, battled dragons, encountered talking animals, and many other fantastical things.
    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";
But she would always have to return back to her dull world of chores and grown-ups.
    return {
And she would often tell them of her latest amazing adventure as a princess.
        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}
But all they would see is a little girl... var littleGirl = princess(); ...telling stories about magic and fantasy.
littleGirl.story();
And even though the grown-ups knew of real princesses, they would never believe in the unicorns or dragons because they could never see them. The grown-ups said that they only existed inside the little girl's imagination. But we know the real truth; that the little girl with the princess inside... ...is really a princess with a little girl inside.

Third Example

Closures are hard to explain because they are used to make some behaviour work that everybody intuitively expects to work anyway. I find the best way to explain them (and the way that I learned what they do) is to imagine the situation without them:
var bind = function(x) {
    return function(y) { return x + y; };
}

var plus5 = bind(5);
alert(plus5(3));
What would happen here if JavaScript didn't know closures? Just replace the call in the last line by its method body (which is basically what function calls do) and you get:
alert(x + 3);

Fourth Example

Now, where's the definition of x? We didn't define it in the current scope. The only solution is to let plus5 carry its scope (or rather, its parent's scope) around. This way, x is well-defined and it is bound to the value 5 This is an attempt to clear up several (possible) misunderstandings about closures that appear in some of the other answers.
A closure is not only created when you return an inner function. In fact, the enclosing function does not need to return at all in order for its closure to be created. You might instead assign your inner function to a variable in an outer scope, or pass it as an argument to another function where it could be called immediately or any time later. Therefore, the closure of the enclosing function is probably created as soon as the enclosing function is called since any inner function has access to that closure whenever the inner function is called, before or after the enclosing function returns.
A closure does not reference a copy of the old values of variables in its scope. The variables themselves are part of the closure, and so the value seen when accessing one of those variables is the latest value at the time it is accessed.

This is why inner functions created inside of loops can be tricky, since each one has access to the same outer variables rather than grabbing a copy of the variables at the time the function is created or called.
The "variables" in a closure include any named functions declared within the function. They also include arguments of the function.
A closure also has access to its containing closure's variables, all the way up to the global scope.
Closures use memory, but they don't cause memory leaks since JavaScript by itself cleans up its own circular structures that are not referenced.
IE memory leaks involving closures are created when it fails to disconnect DOM attribute values that reference closures, thus maintaining references to possibly circular structures.
A closure is much like an object. It gets instantiated whenever you call a function.
The scope of a closure in JavaScript is lexical, which means that everything that is contained within the function the closure belongs to, has access to any variable that is in it.
A variable is contained in the closure if you assign it with var foo=1; or just write var foo;
If an inner function (a function contained inside another function) accesses such a variable without defining it in its own scope with var, it modifies the content of the variable in the outer closure.
A closure outlives the runtime of the function that spawned it. If other functions make it out of the closure/scope in which they are defined (for instance as return values), those will continue to reference that closure.

Fifth Example

function example(closure){
    // define somevariable to live in the closure of example
    var somevariable='unchanged';

    return {
        change_to:function(value){
            somevariable = value;
        },
        log:function(value){
            console.log('somevariable of closure %s is: %s',
                closure, somevariable);
        }
    }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();
Output
somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged

Six example

/*
* When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns
* An important concept to learn in Javascript
*/

function outerFunction(someNum) {
  var someString = 'Hai!';
  var content = document.getElementById('content');
  function innerFunction() {
    content.innerHTML = someNum + ': ' + someString;
    content = null; // IE memory leak for DOM reference
  }
  innerFunction();
}

Seventh example

A closure is not only created when you return an inner function. In fact, the enclosing function does not need to return at all. You might instead assign your inner function to a variable in an outer scope, or pass it as an argument to another function where it could be used immediately. Therefore, the closure of the enclosing function probably already exists at the time that enclosing function was called since any inner function has access to it as soon as it is called.
var i; 
function foo(x) {   
  var tmp = 3;   
  i = function (y) {
        alert(x + y + (++tmp)); 
  }
 } 
 foo(2);
 i(3);

Eighth Example

Your child will be able to follow two-step directions. For example, if you say to your child, "Go to the kitchen and get me a trash bag" they will be able to remember that direction. We can use this example to explain closures, as follows: The kitchen is a closure that has a local variable, called trashBags. There is a function inside the kitchen called getTrashBag that gets one trash bag and returns it. We can code this in JavaScript like this:
function Kitchen () {
  var trashBags = [1, 2, 3]; // only 3 at first

  function getTrashBag() {
    return trashBags.pop();
  }
  // Make getTrashBag be visible outside the kitchen.
  this.getTrashBag = getTrashBag; 
}

var kitchen = new Kitchen();
kitchen.getTrashBag(); // returns 3
kitchen.getTrashBag(); // returns 2
kitchen.getTrashBag(); // returns 1
Further points that explain why closures are interesting: Each time the Kitchen constructor is called with new Kitchen(), a new closure is created. The trashBags variable is local to the inside of each kitchen and is not accessible outside, but the inner function getTrashBag does have access to it. Every function call creates a closure, but there is no need to keep the closure around unless there is some inner function that has access inside the closure, and that could be called from outside the closure. Making getTrashBag be a property of the kitchen does that here.

Ninth Example

 var create = function (x) {
    var f = function () {
        return x; // we can refer to x here!
    };
    return f;
};
// create takes one argument, creates a function

var g = create(42);
// g is a function that takes no arguments now

var y = g();
// y is 42 here

Tenth Example

In computer science, a closure is a function together with a referencing environment for the nonlocal names (free variables) of that function.
Technically, in Javascript, every function is a closure. It always has an access to variables defined in the surrounding scope
Since scope-defining construction in Javascript is a function, not a code block like in many other languages, what we usually mean by closure in Javascript is a fuction working with nonlocal variables defined in already executed surrounding function.
Closures are often used for creating functions with some hidden private data (but it's not always the case).
var db = (function() {
  // create a hidden object, which will hold the data
  // it's inaccessible from outside
  var data = {};
  // make a function, which will provide some access to the data
  return function(key, val) {
    if (val === undefined) { return data[key] } // get
    else { return data[key] = val } // set
  }
  // we are calling the anonymous surrounding function,
  // returning the above inner function, which is a closure
})();

db('x')    // -> undefined
db('x', 1) // set x to 1
db('x')    // -> 1
// it's impossible to access the data object itself
// we are able to get or set individual items

The example above is using an anonymous function, which was executed once. But it does not have to be. It can be na

No comments:

Post a Comment