JavaScript Execution Context, Closure, Eval and “this” Keyword

September 13, 2008 – 8:36 pm by coachwei | Category WebDev |

These are a few key concepts of JavaScript language that developers should know: execution context, activation object, variable instantiation, scoping, closure, eval and “this” keyword. Knowing these would help one tremendously in Ajax development.

For example, when you write an inner function, you know that you can access the local variables defined in the outer function as if they were defined locally. You can also access the global variables. -Why? How does the host environment resolve such variables?

Another example: When you pass arguments to a function, you can access these arguments as if they were locally defined variables. How does this work?

A slightly more involved example that developers must have seem similar code a lot but may not know the “why”:

function outerFunc(outerArg){
   var localVar = 100;

   function innerFunc(innerArg){
      localVar+=100;
       return (outerArg +innerArg + localVar);
    }

   return innerFunc;
}

 var globalVar = outerFunc(200);
 alert(globalVar(300));	//this displays 700
 alert(globalVar(300));	//this displays 800
 globalVar = outerFunc(200)
 alert(globalVar(300));  //this displays 700 again

Why would the 2nd alert box show 800 (means the value of localVar is retained from the first call) while the third alert displays 700 (the value of localVar is not retained from previous calls)? How does it work?

    Key Concepts

  1. Execution Context:
    An execution context is an abstract concept used by the EcmaScript specification and can be conceived (and even implemented) as a set of objects with properties, though not publicly accessible, that encapsulate the context in which a piece of JavaScript code executes. The JavaScript code would rely on its execution context for things like variable resolution and scoping.

    All JavaScript code executes in an execution context. Global code (code executed inline, normally as a JS file, or HTML page, loads) gets executed in a global execution context (in a browser, the global context is typically the window object), and each invocation of a function (possibly as a constructor) has an associated execution context. Code executed with the eval and setTimeout functions also gets a distinct execution context.

    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 that called function returns, control returns to the original execution context and the just finished execution context is available for garbage collection except for cases like closure. Thus running JavaScript code forms a stack of execution contexts.

  2. Activation Object and Variable Object :

    1. Activation Object:
      When an execution context is created, an Activation Object is created. The Activation Object can be considered as a normal JavaScript object with accessible named properties, except that it has no prototype and it cannot be directly referenced by javaScript code.This Activation Object is used for storing context related information such as call arguments and variables, etc. so that they are accessible to the new execution context (see more info on this later in this post).

    2. Variable Object and Variable Instantiation:
      ECMA Specification refers to a “Variable Object” for variable instantiation. “Variable Instantiation” is a process that takes place when the JavaScript host environment processes a piece of script so that it can be executed but before executing the script. In this process, the JavaScript engine prepares(”instantiates”) the local variables, local functions declarations, and arguments to the function call etc. so that these variables are accessible during execution.

      The way that variable instantiation works is to instantiate each of the function’s formal parameters, local variables and inner function declarations as named properties of the Variable Object. In the process, named properties of the Variable object are created for each of the function’s formal parameters. 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). If there is an inner function declaration, a function object is created. This function object is assigned a property of the Variable object with name corresponding to the function name used in the function declaration. The last stage of variable instantiation is to create named properties of the 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.

      However, it is very important to point out that the Activation object is used as the Variable object. Though conceptually they are called out as different objects, they are the same object in reality. This is important as you can see quickly in “scope and scope chain” and “variable resolution” later on.

      It is 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, that allows the identifier arguments to be treated as if it were a function local variable.


  3. Scope, Scope Chain and Variable Resolution:
    Each execution context has an assigned scope when created. A scope can be thought of as an “object” that is associated with a particular execution context (this scope object is actually the Activation Object we mentioned above). A scope chain consists of a list (or chain) of such objects. The scope chain of an execution context is a chain of objects with the current “scope” object on the top, the “scope” object of the calling execution context as the 2nd object on the top, and so on, with the last “scope” object of the chain being that of the global execution context.

    What do scope and scope chain do? They are used for variable resolution. When some JavaScript refers to a variable "foo", the host environment will try to resolve this variable. This resolution process is against the scope chain of the current execution context. First, it will search to see if there is a variable with the same name in the current scope. This is done by checking to see if the current “scope” object has such a named property. Remember that we mentioned Activation Object and Variable Object are the same object, and local variables (including inner function declarations, and function arguments) are instantiated as named properties of the Variable object during variable instantiation. So if the “foo” variable is defined in the local execution context, there must be a property of the Variable object named “foo”. If such a named property is not found, it means this “foo” variable is not defined here. The resolution process will now go down the scope chain and check against the 2nd “scope” object and so on until such such a named property is found or otherwise an “undefined” error happens

    (BTW: Prototype chain is always part of property resolution process and no difference here either. The normal prototype chain lookup process applies when looking for a property with a specific name from a “scope” object: If no such property is found on the object itself, the prototype object will be searched. Still not found, the prototype of the prototype object will be searched. Until either the property is found or the end of the prototype chain is reached).

    Important to point out: each function object has an internal property called [[scope]] (see more info on this later in this post) that consists of a list (or chain) of objects. This [[scope]] property can not be directly referenced by JavaScript code. When the function object is created, its internal [[scope]] property is assigned to the execution context in which this function object is created. This execution context has its own scope object and so on. In the end, the [[scope]] property is associated with a scope chain with the execution context in which the function object is created being on the top.

    The scope chain of the execution context of a function call consists of the list referred to by the [[scope]] property of the corresponding function object and the Activation object created for this function call. The activation object is at the front of the chain (or the top of the list).

  4. Automatic Garbage Collection:
    Yes, automatic garbage collection is not a Java specialty. EcmaScript uses automatic garbage collection too. If an object becomes un-referable (by having no remaining references to it left accessible to executing code), it becomes available for garbage collection and will at some future time be destroyed and any resources it consumes freed and returned to the system for re-use.

    This would normally be the case upon exiting an execution context. Any objects created within the exited execution context, including function objects, would no longer be accessible and so would become available for garbage collection. However, Closure is the exception.

  5. Closure:
  6. A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that “closes” the expression). A closure is formed by returning a function object that was created within an execution context of a function call and assigning an accessible reference to that inner function. The accessible reference can be established by directly assigning the returned function object to a global variable, a property of a globally accessible object or an object passed by reference as an argument to the outer function call, etc.

    In the code example above, line “var globalVar = outerFunc(200);” calls the outer function "outerFunc". This call returns an inner function object and this returned inner function object is assigned to a global variable called globalVar. As a result, a closure is formed here.

  7. Summary and the Global Execution Context

    The key concepts of execution context can be summarized using the following illustrations (assuming the function is named "foo"):

       The Execution Context of a call to function "foo":
               . Activation object
               . Variable object
               . Scope chain
    

    The [[scope]] property of function object “foo” is:

        foo.scope:
              = the scope chain of the execution context where "foo" is created
    

    Further, the relationship between the above objects are:

    
       The Execution Context of a call to function "foo":
             .Activation object: = Variable object
                     .arguments
                     .local variables
                     .local function declarations
             .Scope chain:
                         = Activation object + foo.scope
    

    The global execution context gets some slightly different handling:
    1. As it does not have arguments so it does not need a defined Activation object to refer to them;
    2. The global execution context does need a scope and its scope chain consists of exactly one object, the global object itself (window object).
    3. The global execution context does go through variable instantiation just like any other context;
    4. The global object itself is used as the Variable object, which is why global functions and variables become properties of the global object.

How Does A JavaScript Function Get Executed?

The JavaScript engine goes through several steps in calling a JavaScript function (say the function is named "foo" for reference purposes):

  1. First of all, it creates a new Execution Context for this function call. The creation of an Execution Context follows the following steps:
    1. Create an Activation Object;
    2. Create an arguments object with length and callee properties specified. This argument object is an array-like object with integer indexed members corresponding to the arguments passed to the function call, in the order of their appearance. It also has length and callee properties instantiated. Next, a property named "arguments" is created for the Activation Object and a reference to this arguments object is assigned to this property;
    3. Variable Instantiation: assign local variables, inner function declarations and declared function parameters as such named properties of this Activation Object, with value being “undefined” for local variables and non-instantiated function call parameters (more on the values later, and also more on how functions are instantiated and assigned [[scope]] property later).
    4. Assign the “this” keyword (more on "this" keyword later);
    5. Assign “scope” and “scope chain” to this execution context:

      • “scope” = the Activation Object:
      • “scope chain” = the Activation Object + the chain referred to by the [[scope]] property of this function object “foo”.

    Now the execution context of this function call is created and we are ready to call the function.

  2. Call function “foo” and executes its code line by line:

    • For each variable that the execution process runs into, resolve it according to the variable resolution rule by looking at the local Activation object first, then the calling execution context’s Activation object, and so on, until the end of the scope chain which should be the “Activation Object” of the global execution context (a side note: for performance reasons, you can see why referencing a global variable using window["variableName"] would be better than using "variableName" directly);

    • For each local variable (remember we said earlier that their values are “undefined” during variable instantiation), evaluate the variable’s assignment expression (if there is one) and assigns the result to it (actually, assigns the result to such a named property of the Activation Object);

    • If the execution process runs into a function call (let’s call it function “foo2″), a new execution context (let’s call this “context foo2″) is created for this function call. In “context foo2″:

      1. a new Activation Object (”Activation object foo2″) is created;

      2. Variable Instantiation is performed(using the Activation object(”Activation object foo2″) as Variable object);

      3. The scope chain of “context foo2″ is (”Activation object foo2″+ the scope chain of “foo”);

      4. During the variable instantiation for this function call, if a function declaration (let’s call this function “foo3″) is found, a new function object (”foo3″) is created. a property named as the declared function’s name with value being this newly created function object will be added to the Activation object.

        More importantly to point out, the [[scope]] property of this newly created function object "foo3" is the scope chain of the execution context where the instantiation happens - which is “context foo2″ in this case. So "foo3.scope" is (”Activation object foo2″+ the scope chain of “foo”);


      5. Eventually the function is called. Upon returning from this call, execution continues to the next line of function "foo";



    • Finally, this call to function "foo" completes and we return to the callee. At this moment, unless a closure is formed, this execution context is available for garbage collection.


Function Instantiation

In JavaScript, “functions” are objects. Depending on how a function is defined, there are three ways to instantiate a function object:


  1. from function declaration during variable instantiation:
    If a function declaration is found during the process of variable instantiation, a function object will be created. The Activation Object will have a property whose name is the name of the function and whose value is the created function object. Further, This created function object will have its [[scope]] property assigned to be the scope chain of the execution context in which this function object is created.
    For example, in the following code snippet:

           function outerFunc() {
              var var1=10;
              function MyFunc1(){
                     return  var1=var1+1;
               };
    
              return MyFunc1();
            }
    
           alert(outerFunc()); //displays "11".
    

    When the host environment is going to execute line alert(outerFunc());, in particular, when it is going to call outerFunc(), it will create a new Execution Context for this call (let’s name this new execution context outerFuncContext1 for reference purpose). During the creation of outerFuncContext1, it will instantiate variables. Both "var1" and "MyFunc1" are instantiated during this variable instantiation. Upon variable instantiation, the Activation Object associated with outerFuncContext1 will have a property named "var1" whose value is “undefined”, and a property named "MyFunc1" whose value is a function object created here. Further, the [[scope]] property of this function object is assigned to be the scope chain of outerFuncContext1.


  2. from the evaluation of a function expression during code execution.
    Consider the following snippet:

           function outerFunc() {
              var var1=10;
              var var2=function(){
                     return var1=var1+1;
               };
    
              return var2();
            }
    
           alert(outerFunc()); //displays "11".
    

    When the host environment is going to call outerFunc(), it will create a new Execution Context for this call (again, let’s name this execution context outerFuncContext1 for reference purpose). During the creation of outerFuncContext1, it will instantiate variables. Both "var1" and "var2" are created during this variable instantiation. Upon variable instantiation, the Activation Object associated with outerFuncContext1 will have a property named "var1" whose value is “undefined”, and a property named "var2" whose value is also “undefined”.

    Then the host environment goes on to execute the call to outerFunc(). During execution, first it will assign 10 to var1. Then it will evaluate the function expression related to var2. During this evaluation, a function object is created and assigned to variable var2. Further, the [[scope]] property of this function object is assigned to be the scope chain of the execution context in which this function object is created, outerFuncContext1.


  3. from invoking the Function constructor:
    In this case, the function’s [[scope]] property always refers to the scope chain of the global execution context, which contains only one object, the global object. An example is:

              var y=100;
              var multiply = new Function("x", "return x * y;");
              alert(10); //displays 1000.
    

    In the above example, variable y is being searched in the global context. If there is no global variable named "y", an error will be thrown.

  4. Summary of function [[scope]]:
    In summary, every function object has an internal [[scope]] property that refers to a scope chain. This property is very important for figuring out the scope of execution context and thus variable resolution, etc:

    • If the function object is created from a Function constructor, the [[scope]] property always refers to one object only, the global object. On browsers, it is the "window" object.

    • If the function object is created from either function declaration or function expression evaluation, its [[scope]] property always refers to the scope chain of the execution context in which the function object is created.

The "this" Keyword

One of the most powerful JavaScript keywords is "this" and I am sure that every developer has used it many times. However, it is not straightforward to figure out what it points to.

"this" is typically assigned an object that it points to during the process of creating a new execution context. If the value assigned refers to an object, then property accessors prefixed with the "this" keyword points to the properties of that object. However, if no object can be assigned to it, then the "this" keyword will point to the global object by default.

The next question is how do we know when/whether an Object will be assigned to "this" and who that Object is. For example, consider the following code:

      function redColor() {
                      this.color= 'red';
              }
     alert(redColor.color); //shows "undefined"
     var aa=redColor;
      alert("color="+aa.color); //shows color= undefined

What does not “color” become a property of "aa"? Further, functions are objects in JavaScript - why wouldn’t "this" refer to the function object “redColor” itself?

The rule to remember is that "this" always refers to the “owner” of the function we’re executing. In other words, keyword "this" always refers to the object that the containing function is a method of.

In the above example, the function "redColor" is not a method of object "redColor", so "redColor.color" returns “undefined”. Further, function "redColor" is not a method of some object called "aa" either. So "aa.color" also returns “undefined”.

However, according to our understanding of how variable instantiation works, "redColor" is instantiated as a property of the global object. The global object has a property called "redColor" and the value of the property is the "redColor" function object. In the end, "function redColor" is actually a method of the global object. According to the rule above, "this" should be referring to the global object.

In other words, if we execute function "redColor", we are actually assigning a “color” property to the global object with the value of “red”. If you run the following code:

	function redColor() {
              this.color = 'red';
      }

         redColor();
	 alert("window.color="+window.color);//shows window.color=red

The alert box shows “window.color=red”!

If you attach function "redColor" as a method of an object using obj.method=redColor or obj.prototype.methodName=redColor, the keyword "this" will correctly point to our "obj". However, there is one case that people tend to make mistake, like the following:

          <div id="mydiv" onclick="redColor();">This is my div</div>
"redColor" is still not a method of the “div” object. It is being called by a method of the “div” object called the "onclick". As a result, the "this" keywork in the function body of "redColor" is not pointing to the “div” object as we hoped. The code below is the right way to achieve the goal of adding a "color" property to the “div” Object:
           var div=document.getElementById("mydiv");
           div.onclick=redColor;

The "eval" and "setTimeout" Functions
Function "eval" and "setTimeout" have their own distinct execution context, as mentioned briefly ealier. "setTimeout" always assumes the global execution context. For "eval", here is the quote from ECMASpecification:

“When control enters an execution context for eval code, the previous active execution context, referred to as the calling context, is used to determine the scope chain, the variable object, and the this value. If there is no calling context, then initializing the scope chain, variable instantiation, and determination of the this value are performed just as for global code.

The scope chain is initialized to contain the same objects, in the same order, as the calling context’s
scope chain. This includes objects added to the calling context’s scope chain by with statements and
catch clauses.

Variable instantiation is performed using the calling context’s variable object and using empty
property attributes.

The this value is the same as the this value of the calling context.”

In short, you can think of “eval” assuming the exact same execution context as the calling code.

    Further Readings and References
  1. “Microsoft AJAX Library - JavaScript Execution Context”, http://www.exforsys.com/tutorials/microsoft-ajax/javascript-execution-context/1.html; (quick note: this doesn’t really have anything to do with Microsoft Ajax library. Further, “AJAX” should be spelled as “Ajax”. The “AJAX” spelling is so 2005!);

  2. “Javascript Eval Scope Namespace Execution Context”, http://adrenalin.wordpress.com/2006/06/12/javascript-eval-scope-namespace-execution-context/;

  3. “The Magic Eval”, http://nerd.metrocat.org/2005/09/the-magic-eval;

  4. “The this keyword”, http://www.quirksmode.org/js/this.html;

  5. “Javascript Closures”, http://www.jibbering.com/faq/faq_notes/closures.html(note: this is a master piece!);

Post a Comment