When a javascript function is called, it enters an execution context. If another function is called (or the same function recursively) a new execution context is created, and execution enters that context for the duration of the function call.
When an execution context is created, a number of things happen in a defined order:
- An "Activation" object is created.
- The "arguments" object is created.
- Execution context is assigned a scope, which consists of a list (or chain) of objects. Each function object has an internal scope property that also consists of a list (or chain) of objects. The scope that is assigned to the execution context of a function call consists of the list referred to by the scope property of the corresponding function object with the Activation object added at the front of the chain (or top of the list).
- The process of "variable instantiation" takes place using the Variable object. The Activation object is used as the Variable object (they are the same). Named properties of the Variable object are created for each of the function's formal parameters, and if arguments to the function call correspond with those parameters, the values of those arguments are assigned to the properties (otherwise the assigned value is undefined). Inner function definitions are used to create function objects which are assigned to properties of the Variable object with names that correspond to the function name used in the function declaration. The last stage of variable instantiation is to create named properties of Variable object that correspond with all the local variables declared within the function. The properties created on the Variable object that correspond with declared local variables are initially assigned undefined values during variable instantiation. The actual initialization of local variables does not happen until the evaluation of the corresponding assignment expressions during the execution of the function body code.
- A value is assigned for use with the "this" keyword. If the value assigned refers to an object then property accessors prefixed with the "this" keyword reference properties of that object. If the value assigned (internally) is null, then the "this" keyword refer to the global object.
The fact that the Activation object, with its arguments property, and the Variable object, with named properties corresponding with function local variables, are the same object, allows the identifier arguments to be treated as if it was a function local variable.
The global execution context gets some slightly different handling as it does not have arguments so it does not need a defined Activation object to refer to them. The global execution context does need a scope and its scope chains consist of exactly one object, the global object. The global execution context does go through variable instantiation. Its inner functions are the normal top level function declarations that make up the bulk of javascript code. The global object is used as the Variable object, which is why globally declared functions (as well as globally declared variables) becomes properties of the global object. The global execution context also uses a reference to the global object for the "this" object.
Scope chains and "scope"
The scope chain of the execution context for a function call is constructed by adding the execution context's Activation/Variable object to the front of the scope chain held in the function object's "scope" property. In ECMAScript, functions are objects. They are created during variable instantiation from function declarations, during the evaluation of function expressions or by invoking the Function constructor.
Function objects created with the Function constructor always have a "scope" property referring to a scope chain that only contains the global object.
Function objects created with function declaration or function expression have the scope chain of the execution context in which they are created assigned to their internal "scope" property.
In the simplest case of a global function declaration such as:
function exampleFunction(formalParameter) {
... // function body code
}
the corresponding function object is created during the variable instantiation for the global execution context. The global execution context has a scope chain consisting of only the global object. Thus the function object that is created and referred to by the property of the global object with the name "exampleFunction" is assigned an internal "scope" property referring to a scope chain containing only the global object.
A similar scope chain is assigned when a function expression is executed in the global context:
var exampleFuncRef = function() {
... // function body code
}
except in this case, a named property of the global object is created during variable instantiation for the global execution context but the function object is not created, and a reference to it assigned to the named property of the global object, until the assignment expression is evaluated. But the creation of the function object still happens in the global execution context so the "scope" property of the created function object still only contains the global object in the assigned scope chain.
Inner function declarations and expression result in function objects being created within the execution context of a function so they get more elaborate scope chains. Consider the following code, which defines a function with an inner function declaration and then executes the outer function:
function exampleOuterFunction(formalParameter) {
function exampleInnerFunctionDec() {
... // inner function body
}
... // the rest of the outer function body
}
exampleOuterFunction(5);
The function object corresponding with the outer function declaration is created during variable instantiation in the global execution context so its "scope" property contains the one item scope chain with only the global object in it.
When the global code executes the call to the exampleOuterFunction, a new execution context is created for that function call, and an Activation/Variable object along with it. The scope of that new execution context becomes the chain consisting of the new Activation object followed by the chain referred to by the outer function object's "scope" property (just the global object). Variable instantiation for that new execution context results in the creation of a function object that corresponds with the inner function definition and the "scope" property of that function object is assigned the value of the scope from the execution context in which it was created. A scope chains that contains the Activation object followed by the global object.
So far this is all automatic and controlled by the structure and execution of the source code. The scope chain of the execution context defines the scope property of the function object created, and the scope property of function object define the scope for their execution contexts (along with the corresponding Activation object).
The with statement evaluates an expression, and if that expression is an object, it is added to the scope chain of the current execution context (in front of the Activation/Variable object). The "with" statement then executes another statement (that may itself be a block statement) and then restores the execution context's scope chain to what it was before.
A function declaration could not be affected by a "with" statement as they result in the creation of function object during variable instantiation, but a function expression can be evaluated inside a "with" statement:
var y = {x:5}; // object literal with an x property
function exampleFuncWith() {
var z;
// Add the object referred to by global variable y to the front of the scope chain.
with (y) {
// Evaluate a function expression to create a function object and assign a reference to that
// function object to the local variable z
z = function() {
... // inner function expression body
}
}
}
exampleFuncWith();
When the exampleFuncWith function is called, the resulting execution context has a scope chain consisting of its Activation object followed by the global object. The execution of the "with" statement adds the object referred by the global variable y to the front of that scope chain during the evaluation of the function expression. The function object created by the evaluation of the function expression is assigned a "scope" property that corresponds with the scope of the execution context in which it is created. A scope chain consisting of object y, followed by the Activation object from the execution context of the outer function call, followed by the global object.





