DEV Community

Cover image for JavaScript Demystified:  From Compilation to Execution
Guilherme Scotti
Guilherme Scotti

Posted on • Updated on

JavaScript Demystified:  From Compilation to Execution

We must examine how our code runs when executed to understand better how JavaScript works under the hood. By the end of this post, you should understand what execution context is and why it is essential to understand some core principles of JavaScript, like Hoisting and Closure.

[TL;DR] This explores JavaScript execution and the debate of whether it is compiled or interpreted. JavaScript engines manage code execution through Execution Context and define environments. The compilation phase creates Scope Chain and hoisting while the execution phase brings the code to life.

How does JavaScript work under the hood?

How is JavaScript executed in browsers? Is it compiled or interpreted? There is a lot of debate about whether JavaScript is a compiled or hybrid language. However, one reliable specification is available.

JavaScript is a lightweight, interpreted language MDN

I'm unfamiliar with compilers so that I won't delve into details. However, this knowledge is essential to better understand some of the language's logic.

There is a temptation to think that JavaScript code is interpreted line-by-line, top-down in order, as the program executes and therefore not compiled. However, while that is substantially true, one part of that assumption can lead to incorrect thinking about the language, and that's what we are going to see.

JavaScript is an interpreter-agnostic language

Therefore, the language is interpreted, but there isn't an official JS Engine designed for the language. Web Browser vendors created a lot of Engines, which essentially make all the magic happen.
But that concept diverges a lot; some academics suggest that it is a compiled language, and many blogs and posts say that it is a hybrid language. The official standard specification says:

Therefore the language is interpreted, but there isn't an official JS Engine for the language, and the community created a lot of Engines to suppress that need.

JS Engines

JS Engines

While each JavaScript engine varies in its implementation details, the intention here is not to delve too deeply into those specifics; instead, we will focus on the broader aspects of code execution. These engines play a pivotal role in interpreting JavaScript code, yet they operate under a distinct constraint compared to languages like Java or C#. Unlike languages that undergo extensive compilation before execution, JavaScript engines, whether in a browser or Node.js environment, do not have the luxury of ample compilation time.

As JavaScript code runs, the engine initiates the processing sequence, navigating through a series of steps, with one critical phase being the Execution Context. This context encompasses the environment in which the code is executed, including variables, functions, and the scope chain. Understanding the intricacies of the Execution Context is vital for developers seeking to optimize their code for performance.

Execution Context

Execution context is defined as the environment in which the JavaScript code is executed.

When code is run in JavaScript, the environment in which it is executed is very important. By the environment, I mean variables, objects, this, functions, and every Execution Context in JavaScript must be one of these three types:

  • Global Context: The main execution context in which JS code starts its execution when the bundle first loads at the browser.
  • Function Context: This is the context created by executing the code inside a function, and that environment has access to the global Environment.
  • Eval: An execution context confined within the eval function adds complexity to the script. While subtle, Eval introduces a unique dynamic, influencing the course of execution.

However, to create these kinds of contexts, the Engine must go through a series of stages, and we are going to focus on the two most important stages

  • Compilation / Creation Phase
  • Execution Phase

At the compilation phase, the Engine scans the code line-by-line, top-down, to create the Scope Chain, Hoist variables and functions and determine the value of "this". Essentially, all that happens a few microseconds before the execution phase, thus leading to the misunderstanding between interpreted or compiled language, knowing that it's essential to understand some key concepts of how the language works.

After the compilation phase is complete, the execution of the code starts. Let's visualize it with an example:

//The code simply calls itself 3 times, incrementing the value of ´i´ by 1.
function recursive(i) {
  if (i === 3) {
    return;
  } else {
    recursive(++i);
  }
}
recursive(0);
Enter fullscreen mode Exit fullscreen mode

Execution Context

Every time a function is about to be executed, a context is created for it and added to the Stack. Once all the function's code is executed, JS engines pop out that function. Each function call creates a new context, creating a Lexical Scope where anything declared inside the function can not be directly accessed from outside the current function scope.

Conclusion

Understanding the inner workings of JavaScript execution is crucial for developers. The debate over whether JavaScript is compiled or interpreted has nuances, and it's essential to grasp the role of JavaScript engines in executing code. JavaScript is an interpreter-agnostic language. Therefore, the language is interpreted, but there isn't an official JS Engine designed for the language; due to that, Web Browser vendors created many Engines responsible for interpreting the code and creating the Execution context, which is the environment where the code is executed.

Those environments are created in two stages, the Compilation and the Execution stage, and they are responsible for creating the Scope Chain, hoisting variables and functions, and executing the code.

The heart of this process lies in the Execution Context, where the environment for code execution is defined, comprising Global, Function, and Eval contexts. Delving into the compilation and execution phases unveils the intricacies of creating the Scope Chain, hoisting variables and functions, and determining the value of "this."

Now that you know more about Execution Context, it's time to move to the next chapter of this series of articles and learn more about Hoisting. did you know the term "hoisting" didn't exist at EcmaScript Specification until the ES6 release?

If you want to dive deeper into some concepts, visit the References. Please post any feedback, questions, or requests for topics. I would also appreciate 👏 if you like the post so that others can find this too.

Top comments (0)