How Javascript works under the hood - Execution context & call stack 🔥

How Javascript works under the hood - Execution context & call stack 🔥

·

5 min read

Introduction

In this article, we will learn one of the must-know fundamental concepts of Javascript - Execution context and call stack. Understanding of execution context and call stack will set you up for learning other essential parts of the javascript such as scopes, hoisting, closures, etc.

As software engineers, we break down our code into smaller pieces (functions, modules, packages, etc) in order to manage the complexity of the problem for better readability. Similarly, the javascript engine manages the complexity and execution of the program by breaking it down into smaller pieces for execution, these smaller pieces are known as execution contexts.

What's inside an execution context? 🤔

Execution context is like a block or an environment where javascript code is executed. Everything in javascript happens inside an execution context.

Each execution context has two components:

  1. Memory component (Variable environment)
  2. Code component (Thread of execution)

Similarly, each execution context has two phases:

  1. Memory creation phase
  2. Execution phase
  • In the memory creation phase, variables and functions are declared memory and are stored as key-value pairs in the memory component.
  • In the execution phase, code is executed line by line in the code component.

execution-context.png

There are two types of execution context that gets created throughout the lifecycle of the program:

  1. Global Execution Context - gets created whenever the program starts running.
  2. Function Execution Context - gets created whenever any function is invoked.

Global Execution context (GEC) 🌎

Global execution context is the first execution context that gets created whenever we run the code. There can be only one GEC.

A) In the memory creation phase of the GEC inside the memory component, the Javascript engine will:

  1. Create a global object.
  2. Create a this object.
  3. Set up memory space for variables and functions.
  4. Assign the variables a default value of undefined and function declaration are stored as key-value pairs.

Note: In the browser, the global object would be window and in the Nodejs environment, the global object would be global. We will assume a browser environment for the following example.

Let's understand this concept with a simple example that returns the square of a number.

var num = 10;
function square(num) {
  var result = num * num;
  return result;
}
var ans = square(num);

From the above example in the memory creation phase of GEC, image.png

  1. window object is created
  2. this which in the GEC points to the window object (browser environment).
  3. num and ans are assigned a default value of undefined
  4. Any function declarations, (square function in this case) are entirely placed into the memory.

B) In the execution phase of the GEC in the memory component, the Javascript engine starts executing the code line by line.

image.png

From the above example in the execution phase,

  1. num is assigned 10
  2. ans is assigned the result 100 that is returned after invoking the square function.

Function Execution context (FEC) ✨

Execution context is created only two times throughout the lifecycle of the program. Once, when Javascript starts executing the code that is a global execution context and another time an execution context is created whenever we invoke a function that is a function execution context.

Similar to the GEC, the following things happen in FEC with an exception. In the memory creation phase of the FEC, the Javascript engine will:

  1. C̶r̶e̶a̶t̶e̶ a̶ g̶l̶o̶b̶a̶l̶ o̶b̶j̶e̶c̶t̶ Create an arguments object.
  2. Create a this object whose value depends on what context a function is called (We will have separate blog for demystifying this keyword).
  3. Set up memory space for variables and functions.
  4. Assign the variables a default value of undefined and place any function code as a key-value pair.

Note: Arrow functions don't get their own arguments and this object. They use the closest surrounding function's arguments and this object.

A) From the above example in the memory creation phase, image.png

  1. this object is created whose value depends on which context the function was called. In the above example, it refers to the window object.
  2. arguments objects get created which will contain parameters of the functions as keyed collections.
  3. num is assigned the value that is been passed as a parameter to the square function that is 10.
  4. result will contain undefined.

B) From the above example, in the execution phase - image.png

  1. result variable will have a value of 100 which is calculated after executing line number 3.

Call stack 📚

Don't you think this is too much for the javascript engine to handle? This is where call stack comes into the picture. Call stack maintains the order of execution of the execution contexts. Javascript is a synchronous single-threaded language. That means, Javascript can execute only one command at a time in a specific order and the order of execution is maintained by the call stack.

From the above example,

  1. Whenever a program starts running, the global execution context is created and pushed onto the stack.
  2. When the square function is invoked, a function execution context is created and pushed onto the stack.
  3. Once the square function is done executing, it returns the result and the control of the program where the function was originally invoked.
  4. After this, the square function is popped off from the stack.
  5. Once the last line is done executing, the execution of global execution context is finished and it is popped off from the stack and the call stack becomes empty.

Summary ✨

👉 Whenever the Javascript engine starts executing the code, a Global Execution Context is created.

👉 Execution context has two components - the memory component and the code component.

👉 Execution context has two phases - the memory creation phase and the execution phase.

👉 The next type of execution context is the Function Execution context that gets created whenever a function is invoked.

👉 Call stack maintains the order of execution of the execution contexts.

If you found this article helpful, feel free to like, comment, and share this article. You can reach out to me on Twitter or Linkedin to discuss anything around web ecosystem. Thank you for reading, have a nice day! 🤗