Javascript in action: Under the hood 🧐

Javascript in action: Under the hood 🧐

All secret lies here 😎

Β·

5 min read

Javascript is a popular programming language with many peculiar behaviors which can sometimes blow your mind. Blow mind gif But if you get to know how it works under the hood, you will just love it resulting in a master of it. To really understand its working, two thing needs to be clearly understood.

1. Everything in Javascript happens inside an Execution Context πŸ“¦

Now, what is this Execution Context that came in between you, me, and Javascript? You and me gif Don't worry, that is the main hero of this blog. Let me get introduce it to you.

You can think of Execution Context as a box divided into two compartments, namely, Memory and Code. The memory compartment consists of all variables and function definitions that are defined in your program as key-value pairs. It has also a good name which you can call i.e., Variable Environment. The second compartment is known as Code Execution or Thread of Execution, where your Javascript code executes line by line.

2. Javascript is a synchronous single-threaded language🧡

This means that Javascript can run a single line of code at a time and only after its completion, it can move to the next line of code for execution.

Enough theory, let's get into some visualization. Enough of this sh*t gif

Under the hood 🧐

I'm going to consider this block of code for the explanation -

var a = 10;
var b = 20;
function add (num1, num2) {
    var sum = num1 + num2
    return sum;
}
var c = add(a, b);

This is what you write in your code editor. Now, let's see how this is interpreted by the JS Engine. As soon as this code is run, an execution context is created. Basically, there are two phases that go on inside this execution context.

  • The first phase, known as the memory allocation phase where Javascript goes through the entire code at once and allocates memory to each variable and functions with a special placeholder called undefined and then stores them in the Variable Environment as a key-value pair. So after the memory allocation phase, the execution context may look something like this (Imagine the below code block as an execution context box) -

    //Global Execution Context
    //Memory allocation phase
    
                      Memory                        Code Execution
                  a: undefined
                  b: undefined
      add: {...} //function code
                  c: undefined
    

    This is what execution context looks like on a browser. Execution context.jpg One thing to be noticed here is that Javascript stores the entire function code itself as a value. Interesting right? I hope this visualization makes a much clearer view of the execution context. Let us carry on.

  • After the memory of all variables and functions are allocated successfully, Javascript starts interpreting the code, and this phase is known as the code execution phase. Here Javascript performs calculations present within the program.

Line 1: Javascript encounters a variable named a having a value of 20. So it goes to the variable environment and updates the value of a from undefined to 20. This looks something like this - Execution context2.jpg

Line 2: Same goes for the variable b. It is updated from undefined to 10.

Line 3: Javascript sees a function block and will skip it from line 3 to line 5.

Line 7: Javascript encounters the function invocation statement and goes back to line 3 to execute the function block.

Up to this, the GCE (Global execution context) looks something like this - Execution context3.jpg

An important thing to note here is that as soon as function add is invoked, a brand new execution context is created inside the global execution context (GCE) having its own local scope. Again, this execution context will be having two components and two phases as the previous one. After memory allocation to all the function variables, the Global Execution Content (GCE) looks like -

//1. Global Execution Context
//2. Code execution phase
//3. Initiation of function execution context
//4. Memory allocation phase

            Memory                                 Code Execution
            a: 10                                    var a = 20
            b: 20                                    var b = 10
add: {...} //function code                     result = sum(a, b)
    result: undefined
                                          //Function execution context
                                            Memory         Code Execution
                                    num1: undefined
                                    num2: undefined
                                    sum: undefined

This is the same on the browser. Execution context4.jpg

Line 3: The function gets its parameters from the arguments passed to it from line 7 and initializes num1 and num2 with their updated value in memory.

Line 4: Calculations are performed and the result is stored in sum and its value in memory is updated.

Line 5: return keyword is encountered. This tells the function to return the control back to the line where it has come from. So, here it is line 7. It also says return sum which means it returns taking the value of the sum along with it.

Now, as soon as this function block is executed and has returned, its execution context is completely deleted, and also after the program has been completed, the GCE also gets deleted. Let us view the whole process quickly in a single shot. final_60f7be1ff1813800c7f3d176_461114.gif This was a huge thing to understand. Tired gif

Managing nested execution contexts

Suppose, you have multiple nested function calls. Managing all those execution contexts one after another will be a tedious task. So how does Javascript handle this do you know? This is going more interesting now. Interesting gif Javascript uses a stack to manage all the execution context which is popularly known as the call stack. Other names are -

  • Execution Context Stack
  • Program Stack
  • Control Stack
  • Runtime Stack
  • Machine Stack

When a Javascript program runs, the call stack is populated with GEC and as and when new execution contexts are formed they are pushed into the stack. Subsequently, when execution contexts are deleted they are popped out of the stack. Finally, after the program execution is completed, the GEC also gets popped out of it. Let's visualize this quickly. final_61084db0f8e07b00d3241446_17795.gif In this way,

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

Wrapping up

Hope this article was helpful 😊. If so, then do give a reaction and share with others. Want to add something? Write it in the comments πŸ‘‡