|Written by Ian Elliot
|Thursday, 01 May 2014
Page 3 of 3
As the lifetime of a Function object only depends on what variables reference it, just like any other object, it can exist well after any outer function that created it.
By the rules of nested scope the inner function has access to the variables in the outer function.
The idea of a closure simply extends this access to all times.
In other words nested scope persists beyond the evaluation of the outer function and beyond the lifetime of the outer function.
If this wasn't the case then having inner Functions with their own lifetimes and nested scope would be very complicated.
The rule would have to be something like - an inner function has access to the local variables of an outer function but only while the function is being evaluated. If you evaluated the inner function at some later time then you could simply get an error message because variables that you could access at one time are no longer accessible.
Using a closure means that the inner function always has access to the same variables no matter when it is evaluated.
To be more precise a when a Function object is created all of the variables which are in scope, including those of any outer functions are stored in an execution context - this what was explained right at the start.
What is new is that the execution context stays with the Function object even when the variables no longer exist because function body which created them has finished running or the Function object that it belongs to has been garbage collected.
As another example consider:
The first line of myFunction creates a local variable message which is added to the execution context and set to "Hello Closure". Next an inner function is defined and a reference to it is stored in the Global variable myInnerF. The function body shows an alert box with what is stored in message and then it changes the message. This demonstrates that you can access and change what is stored in a variable that is provided courtesy of a closure.
With this definition you can now do the following. First you can execute myFunction;
This evaluates the body of the function and hence results in the creation of the Function object with the function body:
Notice the inner function is not evaluated this just sets up the Function object and its function body.
Now you can set the variable myFunction to null which results in there being no more references to the outer Function object and so it is garbage collected - that is its Function object no longer exists and the message variable should no longer exist.
Even so you can still evaluate the inner Function object. The first time:
you will see "Hello Closure" and the second time you evaluate it
It seems the message variable is alive and well even if the Function object and its function body are most certainly not.
When you first encounter the idea of a closure it seems complicated and arbitrary - why do this?
Once you follow the fact that functions are just objects and a Function object can live longer than the Function object that created it you begin to see why closures are natural.
They are a natural consequence of letting an inner function access the variables of all of the outer functions that contain it.
To make this work a Function object has to capture all of the variables that are in scope when it is created and their values when the outer functions has completed.
This last point is subtle.
See if you can work out what happens if we make a small change to the last example and if you can also work out why it happens:
The only change is that now message is defined after the inner function. You might reason that message isn't in scope but that would be to forget hoisting.
If you recall all variable declarations are moved by the compiler to the top of the function they occur in. So the code is equivalent to:
This means that the variable is in scope and even though it isn't assigned to until the end of the outer function, i.e.after the definition of the inner function, its final value is part of the closure. The reason is that the execution context stores the variables and their changing values until the outer function stops. So the new version still displays the two messages as before.
The Function statement
In an ideal world the account of the Function object would come to an end at this point - you have enough to write any program you care to but not in a style most programmers would recognise.
This results in a Function object with the specified parameters and function body being created - as before.
What is new is the functionname. This isn't a variable but something managed in a different way. In particular the declaration of a function in this way is hoisted just like a var declaration.
Function names can be assigned to and generally treated like variables but they are also used by debuggers to report information on functions and how you are using them.
Apart from hoisting and the special status of a function name as opposed to a standard variable there isn't much difference between the three different ways of creating a Function object.
There is a newer version of the draft of the book here.
More functions - parameters, pass by value, expressions, methods, execution context aka this.
To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, Facebook, Google+ or Linkedin, or sign up for our weekly newsletter.
or email your comment to: firstname.lastname@example.org
|Last Updated ( Sunday, 10 May 2015 )