Execution context JavaScript

Yes, Javascript (JS) is an interpreted language, still has its own form of a compiler, run in what’s known as the Javascript engine.

Every web browser has its own form of a JavaScript engine Eg. Chrome has v8 and Mozilla has spider monkey etc, though they all have the same purpose. JavaScript engines simply convert JavaScript source code into a language the compiler can understand, then executes it.

Let’s start then,

Execution Context

An environment in which the javascript code runs is what form an execution context.

The execution context decides what particular piece of code has access to variables, functions, objects, etc.

If you have read the scope article then you should know what’s the global scope and local scope(function scope).

So similarly execution context have different types —

1. Global Execution Context

Whenever the code runs for the first time or when the code is not inside any function then it gets into the global execution context. There is only one global execution context throughout the execution of code.

In the case of browser global execution context does 2 things

  1. Create a ‘window’ object.
  2. The window object is referenced to ‘this’ keyword.

2. Function Execution Context

Whenever the code execution found a function it creates a new function execution contexts. There can be any number of function execution contexts.

Above, Global execution context contains ‘name’ variable and a function reference to ‘func1’. Whereas three function execution context containing variables and function reference will be created. The Details is explained further in the article.

Execution Stack / Call Stack

Javascript can only run one thing at one time in the browser that means it is the single thread so it queues the other action, events, function in what is called as the execution stack.

Whenever a script load in the browser, the first element in the stack is the global execution context. However, when a function executes, an execution context is created and virtually placed on top of the global execution context. Once a function has finished executing, it gets popped off of the execution stack and returning control to the context below it.

Let’s take an example and visualize the above.

Step1: When the above code loads in the browser, the Javascript engine creates a global execution context and pushes it to the current execution stack.

Step2: Let’s assume that at last, we do a func1() call then the Javascript engines creates a new execution context for that function and pushes it to the top of the global execution context

Step3: Inside the func1() we have func2() call therefore the Javascript engines creates a new execution context for that function and pushes it to the top of the func1 execution context.

Step4: When the func2() function finishes, its execution context is popped off from the current stack, and the control reaches the execution context below it, that is the func1() function execution context.

Step5: When the func1() finishes, its execution stack is removed from the stack and control reaches the global execution context. Once all the code is executed, the JavaScript engine removes the global execution context from the current stack.

Execution Context Phases

There are mainly two phases of the execution context.

  1. Creation
  2. Execution

Let’s take a look one by one

Creation phase

There are several things that happen here before the function execution happen.

  1. At first, a connection to the outer environment is created for each function or variables which is what form a scope chain. This tells the execution context what should it contain and where should it look for resolving the reference for function and values for variables.
  • For the global environment, the outer environment is null. However, all environments within the global, have the global environment as its outer environment.
  • If function ‘a’, contained in function ‘b’, that means ‘a’ has an outer environment ‘b’.

2. After scanning the scope chain an environment record is created where the creation and reference for global context(would be a window in a web browser), variable, function, and function arguments are done in memory.

3. At last value of ‘this’ keyword is determined (In the case of the global execution context, ‘this’ refers to the window) inside each execution context created in the 1st step.

Note: If you find difficulty in understanding this keyword behavior then I highly recommend this.

Therefore we can represent the creation phase as

creationPhase = {
'outerEnvironmentConnection': {
/* scope chain resolution*/
},
'variableObjectMapping': {
/* function arguments, parameters, inner variable and function declarations are created or referenced in memory */
},
'valueOfThis': {},

}

Execution Phase

This is the phase where the code starts to run in the execution context formed in the creation phase and variable values are assigned line by line.

As the execution start, the engine looks for reference to execute the function in its creation phase object. If it doesn’t find it in its own, it will continue to move up the scope chain until it reaches the global environment.

If no references are found in the global environment it will return an error. However, if a reference is found and the function is executed correctly, the execution context of this particular function will be popped off the stack and the engine will move onto the next function, where their execution context will be added to the stack and executed, and so on.

Let's look at the above two phases via example to get a better idea around it.

So the global execution context will look something like this during the creation phase:

globalExecutionObj = {
outerEnvironmentConnection: null,
variableObjectMapping: {
name: uninitialized,
title: undefined,
date: uninitialized,
func1: func,
},
this: window //Global Object
}

Note: Above, the let (name)and const (date) defined variables do not have any value associated with them during the creation phase, but var (title)defined variables are set to undefined.

This is the reason why you can access vardefined variables before they are declared (though undefined) but get a reference error when accessing letand const variables before they are declared.

This is, what we call hoisting i.e all variable declarations using

globalExecutionObj = {
outerEnvironmentConnection: null,
variableObjectMapping: {
name: uninitialized,
title: undefined,
date: uninitialized,
func1: func,
},
this: window //Global Object
}
3 are hoisted/lifted to the top of their functional/local scope (if declared inside a function) or to the top of their global scope (if declared outside of a function) regardless of where the actual declaration has been made.

During the execution phase, the variable assignments are done. So the global execution context will look something like this during the execution phase.

globalExectutionObj = {
outerEnvironmentConnection: null,
variableObjectMapping: {
name: "overflowjs.com",
title: "Execution context",
date: "5 july 2019",
func1: pointer to function func1,
},
this: window //Global Object
}

Note: During the execution phase, if the JavaScript engine couldn’t find the value of let variable at the actual place it was declared in the source code, then it will assign it the value of undefined.

Now, when ‘func1’ is reached a new function execution context will be formed, whose creation object look like below

func1ExecutionObj = {
outerEnvironmentConnection: Global,
variableObjectMapping: {
arguments: {
0: 10,
length: 1
},
num: 10,

author: undefined,
val: uninitialized,
func2: undefined
fixed: uninitialized
addFive: pointer to function addFive()
},
this: Global Object or undefined
}

During the execution phase,

func1ExecutionObj = {
outerEnvironmentConnection: Global,
variableObjectMapping: {
arguments: {
0: 10,
length: 1
},
num: 10,

author: "Deepak",
val: 3,
func2: pointer to function func2()
fixed: "Divine"
addFive: pointer to function addFive()
},
this: Global Object or undefined
}

After the function completes its execution, the global environment is updated. Then the global code completes and the program finishes.

Please consider entering your email here if you’d like to be added to my email list and follow me on medium to read more article on javascript and on github to see my crazy code. If anything is not clear or you want to point out something, please comment down below.

What is function execution context?

Functional execution context (FEC): Functional execution context is defined as the context created by the JS engine whenever it finds any function call. Each function has its own execution context. It can be more than one.

What is the difference between execution context and scope in JavaScript?

Context is related to objects. It refers to the object to which a function belongs. When you use the JavaScript “this” keyword, it refers to the object to which function belongs. Scope refers to the visibility of variables, and content refers to the object to which a function belongs.

What are contexts in JavaScript?

In JavaScript, “context” refers to an object. Within an object, the keyword “this” refers to that object (i.e. “self”), and provides an interface to the properties and methods that are members of that object. When a function is executed, the keyword “this” refers to the object that the function is executed in.

What are the two components of a JS execution context?

Each execution context has two phases: the creation phase and the execution phase.