Page 1 of 2 When you first meet it closure seems like the craziest of ideas. However once you realize that JavaScript functions are objects and what this implies then it seems like a natural consequence.
This is an extract from the book Just JavaScript by Ian Elliot.
Buy Now: from your local Amazon
Just JavaScript An Idiomatic Approach
A Radical Look At JavaScript
Most books on JavaScript either compare it to the better known class based languages such as Java or C++ and even go on to show you how to make it look like the one of these.
Just JavaScript is an experiment in telling JavaScript's story "just as it is" without trying to apologise for its lack of class or some other feature. The broad features of the story are very clear but some of the small details may need working out along the way - hence the use of the term "experiment". Read on, but don't assume that you are just reading an account of Java, C++ or C# translated to JavaScript - you need to think about things in a new way.
Just JavaScript is a radical look at the language without apologies.
Contents
- JavaScript – Essentially Different
- In The Beginning Was The Object
- Real World Objects
- The Function Object
Extract - The Function Object Extract - Function Object Self Reference
- The Object Expression
- Function Scope, Lifetime & Closure
Extract Scope, Lifetime & Closure Extract Execution Context ***NEW!
- Parameters, Returns and Destructuring
Extract - Parameters, and Destructuring
- How Functions Become Methods
- Object Construction
Extract: - Object Factories
- The Prototype
Extract - ES2015 Class and Extends
- Inheritance and Type
- The Search For Type
- Property Checking
Buy Now: from your local Amazon
Also by Ian Elliot JavaScript Async: Events, Callbacks, Promises and Async Await Just jQuery: The Core UI Just jQuery: Events, Async & AJAX
<ASIN:1871962579>
<ASIN:1871962560>
<ASIN:1871962501>
<ASIN:1871962528>
In this chapter we look at some of the more advanced ideas involved in JavaScript functions leading up to the very useful, but often misunderstood, idea of closure. Most of the complexities arise from the simple fact that once you have a Function object you can execute its code and this code can in turn create variables and most importantly additional Function objects.
Scope and the Execution Context
Now we come to the much talked about idea of scope and how JavaScript implements it.
Scope refers to which variables you can access at any point in code.
Before we go on it is worth considering where the variables that are declared in the function body live. They are clearly not properties of the Function object. In fact, they don't even exist except when the function body is being evaluated.
That is, all of the variables in the function body are created when the function body is evaluated and destroyed again when it finishes.
What happens is that when a function body is evaluated, an Execution Context EC is created which stores all of the variables that are accessible from the code. You can think of the EC as being an object with properties that are the variables that are in scope – although you can't directly access the EC and it is an implementation detail.
If you remember from Chapter 2 that variables you create outside of a function are in fact properties of the global object, you can see that the global object plays the role of an EC object for code that lives outside of a function. You can also think of the code that you write outside of a function, i.e. at the global level, as being the function body of the global object – but this is perhaps an abstraction too far.
That is, when the function body is evaluated the variables that are in scope form the execution context.
In the case of JavaScript the scope rules are very simple but only if you realize that you are working with Function objects and not functions.
In JavaScript variables are said to have function scope.
This means that when a function body is evaluated the variables that are created are only accessible within that function.
That is, all variables declared within a function are essentially "local" variables and override any variables already declared elsewhere.
Notice that all local variables only exist while the function is executing – they are not properties of the object. That is, local variables are created anew each time the function is executed.
Things are a tiny bit more complicated than this because JavaScript, like most other languages, actually allows nested function scope in that any function can make use of variables defined in any function that contains it.
We need to consider what "contain" means.
In JavaScript objects can “contain” other objects as properties.
In the same way a Function object can contain other objects as properties, but in addition a Function object can create additional Function objects when its function body is evaluated.
For example:
var myFunction= function(a,b){
var ans=a+b;
var myInnerF=function(){
alert(ans);
};
return ans;
};
Notice that we have a new Function myInnerF created when myFunction is evaluated.
In this case we say that myInnerF is "nested" within, or contained within myFunction.
This doesn't mean that myInnerF is somehow a property of the myFunction Function object. What it means is that myInnerF is created when myFunction is evaluated. It is the declaration of the new function that is nested within myFunction. There is no sense in which the Function object created is in any way contained or nested within the Function object referenced by myFunction.
The new Function object is exactly like any other Function object and it is referenced by a local variable myInnerF of the function body.
Also notice that a new Function object is created each time myFunction is evaluated. This is often a cause of inefficiencies because it is easy to forget that functions are really Function objects. When myFunction finishes evaluating, the local variable, myInnerF, is destroyed and eventually so is the object it references when it is garbage collected by the JavaScript engine.
At this point it looks as if declaring a function inside of another function simply changes how long the inner function lives but there is more to it.
The "nested" scope means that myInnerF can not only access its own local variables, it can also access any variables that are local to the containing function i.e. myFunction in this case. As you can see in this example it makes use of ans which is local to myFunction.
The nested idea applies when multiple functions are nested inside each other. Each inner function has access to its own local variables and the variables of all of the functions that contain its declaration.
So in this case both myFunction and myInnerF also have access to the variables defined within the Global object. In this sense all functions are nested within the Global object.
This notion of nested scope when functions are objects is a very subtle idea.
The reason is when you look at the function body of a Function object there is a tendency to think that it is being executed as you read it.
This isn't the case.
If you look at our example, first the outer Function object is created and its function body is stored.
When you execute the outer function body, at some later time the inner Function object is created but its code isn't executed until it is invoked perhaps at a much later time. In this particular example the inner function isn’t evaluated but it can be and this has some strange consequences because of nested scope.
Lifetimes
The fact that a function is actually a Function object makes it possible for the function to exist in its own right independently and irrespective of how and when its function body is evaluated. The local variables of a function only exist when it is being executed but its properties exist at all times.
This is another strange idea if you are familiar with functions in other languages.
Function objects exist complete with any properties you may have defined even when they are not being evaluated.
If you are going to understand some of the more subtle ways that JavaScript works you have to be 100% clear about the lifetime of a function object.
When a Function object is created as part of some code, the Function object is created and it exists within the whole program just like any other object.
As already explained, JavaScript provides automatic garbage collection which removes any object that has no references to it. So an object, any object including a Function object, exists as long as there is at least one reference to it.
Now consider the implication for the nested function that we have looked at in the previous section:
var myFunction= function(a,b){
var ans=a+b;
var myInnerF=function(){
alert(ans);
};
return ans;
};
As already explained, the inner Function object referenced by myInnerF doesn't exist until the outer function is evaluated. That is when you write:
myFunction(1,2);
the inner Function object is created when the system reaches the line
var myInner= etc.
This Function object exists from that point on till the end of the outer function i.e. until after the return ans; statement.
At this point the variable myInner goes out of scope and no longer exists. With no variables referencing the inner Function object it is soon garbage collected and so in effect as soon as the outer function ends the inner function no longer exists – not quite true but close enough for most purposes.
So this is a bit restrictive in that the only code that can ever evaluate the inner function has to be part of the outer function body. The reason is that this is the only place that the myInnerF variable is in scope.
|