JavaScript Execution Context

JavaScript developers do not pay attention much on internals of JavaScript execution, namely execution context. Even experienced JavaScript developers may lack necessary knowledge about execution context.  Nevertheless, concept of execution context is simple. It consists of details for the environment of a function that is executed. To make execution context more clear,  we will try to give some insight for understanding of execution context.
First of all, there are two types of execution context : first one is the global and second one is the functional. Global context can be accessed from anywhere in the program while functional context  can be accessed by function itself and inner functions of it. Accessing parent function context results in Scope Chains, which is ability to access scope of calling function. Let’s examine global and functional context with an example.

//global context
var x = 1;
function foo(){
   //foo context
   var y = 2;
   //console.log(x+","+y+","+z); (1)
   return function inner(){
      //inner context
      var z = 3;
      console.log(x+","+y+","+z); //(2)
   }
}
//console.log(x+","+y+","+z); (3)
foo()();

From the above code snippet, first(1) log will give a reference error because of the variable z, second(2) log will execute just fine and the third(3) log will give a reference error for y.  The references errors occur because current execution context cannot resolve the identifiers. But, each inner function can see its outer function variables. After giving this basic example, let’s dive into details.
JavaScript Execution Context
Browsers interpret JavaScript single threaded, which means one thing can be done at one time. Similarly, we can see one execution context at one time. When a page loads, global execution context is created and put into execution context stack. After that, interpreter creates a new execution context for each function call while preserving scope chains. Besides, each created execution context is put into stack with respect to their order. When any of execution context is finished, interpreter removes it and continues to execute previous execution context. Below, you can see the figure representing stack for execution context.
Moreover, execution contexts have a life cycle, that can be divided into creation and execution phase. In creation phase, interpreter follows the steps below:

  1. Each variable, function or argument is created.(Variable Object is created)
  2. Scope Chain is initialized.
  3. Value of “this” is determined.

In execution phase, code is interpreted and executed. Now, let’s observe each steps of creation phase thoroughly.
In creation phase, variable object is created first. Then, arguments object is created. After setting necessary objects, interpreter scans for function declarations and creates a corresponding property for each function in variable object. If there is already reference for the function in variable object, interpreter just overrides it. The same process followed for variable declarations but interpreter just passes declarations that already exists in variable object. After finalizing variable context, scope chain is created and we are ready to run the function. Let’s see below function and how it looks like in creation stage.

function foo(z){
   var x = "Hello World!";
   var y = function(){
      alert(x);
   };
   function f(){};
}
foo(13);

Our function looks like as follows in creation stage.

executionContextForFoo(){
   variableObject : {
      arguments : {
         0 : 13,
         length : 1
      },
      z : 13, // Remember, reference to functions created first.
      f : pointer to the function f 
      x : undefined,
      y : undefined
   },
   scopeChain : {...},
   thisForFoo : {...}
}

At this point, hoisting occurs since we first create pointers to the functions and variables, then execute. Let’s look at below example.

(function(){
    alert(typeof hello);//prints pointer to hello function
    alert(typeof hi);//prints undefined
    var hi = function(){
       alert("Hi!");
    }
    function hello{
       alert("Hello!");
    }
})();

Function decelerations are always hoisted, any variable is initialized to undefined. In above example, “hi” is a variable and defined as undefined in variable object.
In short, we have tried to explain execution context and give an overview.
A similar post on Execution context can be found at David Shariff’s post. You can also find some extra information from John Resig’s Learning Advanced JavaScript.
For more information, you can follow below link.
Ecma-262

Written by Yusuf Aytaş

2 Comments

  1. Yusuf Aytaş

    Before writing mine, I had looked at David’s post but forgot to give a reference. Now, I have added reference to his post.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>