Welcome!

Coach Wei

Subscribe to Coach Wei: eMailAlertsEmail Alerts
Get Coach Wei via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: RIA Developer's Journal, JavaScript

RIA & Ajax: Article

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

These are a few key concepts of JavaScript language that developers should know

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).

  1. 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.

  2. Closure:

    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.

  3. 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/;
    http://nerd.metrocat.org/2005/09/the-magic-eval;
  3. “The Magic Eval”,
  4. “The this keyword”, http://www.quirksmode.org/js/this.html;
    “Javascript Closures”, http://www.jibbering.com/faq/faq_notes/closures.html(note: this is a master piece!);

More Stories By Coach Wei

Coach Wei is founder and CEO of Yottaa, a web performance optimization company. He is also founder and Chairman of Nexaweb, an enterprise application modernization software company. Coding, running, magic, robot, big data, speed...are among his favorite list of things (not necessarily in that order. His coding capability is really at PowerPoint level right now). Caffeine, doing something entrepreneurial and getting out of sleeping are three reasons that he gets up in the morning and gets really excited.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.