JavaScript is always hosted to execute in some environment which initially started with browsers followed by server side scripting with Node.js and also some applications that accept JavaScript code as input. Here we will focus on browsers. Different browsers have different JavaScript engines to parse and execute our code.

JavaScript engine is a computer program that executes JavaScript (JS) code. The first JavaScript engines were mere interpreters, but all relevant modern engines utilize just-in-time compilation for improved performance

The first thing that happens within the JavaScript engine is parsing of our code by parser. A parser basically reads our code line by line and checks it for errors and stops execution if any, if the code is free of syntactic errors, the parser produces a data structure called abstract syntax tree, which is then translated to machine code and thus results to output.

Abstract syntax tree (AST), or just syntax tree, is a tree representation of the abstract syntactic structure of source code written in a programming language. Each node of the tree denotes a construct occurring in the source code — Wikipedia

To understand JavaScript code execution, we need to go through and understand two important concepts execution context and execution stack.

Execution Context:

The environment in which our code runs is known as execution context and is defined as one of the following

1. Global — Default environment where code is executed first time.

2. Local/ Function — When the code within the function gets executed.

3. Eval — when the text within the eval gets executed.

// Global context var person = 'john'; const func1 = function() { // execution context. let address = 'New York'; func2(); console.log(`${person} ${address}`); } const func2 = function() { // execution context. let designation = 'Software Developer'; let address = 'Melbourne' console.log(`${person} ${designation} ${address}`); } func1();

console.log(window.person === person) Output:

john Software Developer Melbourne

john New York

true

Lets us understand above example, variable person is defined in the global context and global context is used to execute the code that is not part of any function. Whenever a function is called a new execution context is created and is pushed on top of the current context thus creating what is known as execution stack.

Note: Here we see window.person ===person gives result of true but if we do window.func1(), this would give us TypeError. Below is the brief about this behaviour.

Global Environment Record actually consists of two environment records:

A declarative environment record and an object environment record.

The object environment is backed by the global object, i.e. window and contains var declarations and other globals that the browser provides.

The declarative environment contains the let, const, class, etc declarations. —

Credits stackoverflow.

Execution Stack:

JavaScript as we know runs its operations on a single thread, which means only one action can take place at one time and rest is pushed onto a stack known as execution stack which follows the principle of stack LIFO.

In nutshell we can say the important aspects of execution stack is its nature of synchronous behaviour along with one global context and many functional/local context.

Execution context phases:

The execution context is divided in two stages Creation and Execution phase.

Creation phase: This phase is defined when the function is called before any code is run within.In the creation phase first comes the creation of variable object followed by scope chain and lastly the “this” is determined and set which together form the properties of execution context object.

The variable object is created by following these steps in the process

Adding the argument object containing all the objects that were passed in function call. For each function a property is created in Variable object, pointing to the function i.e. all the functions will be stored in the object before the code starts execution. Variable declarations are looked up and for each variable a property is set in Variable object and set to undefined.

The last two points are generally known as hoisting. Functions and variables are hoisted which means they are available before the execution phase starts but there is a small catch both are hoisted differently, variables are defined only in execution whereas the functions are already defined. Let’s see an example with a bit of surprise too.

// with var/ ES5 function func1() {

console.log('Args:', typeof arguments); console.log('typeof func2:', typeof func2); console.log('typeof variable:', typeof person); console.log('Args:', arguments); console.log('variable:', person); console.log('function assignment:', getName); var person = 'Paul';

var getName = _getName(); function func2() {

console.log('USA');

} func2();

} function _getName() {

return 'Steve';

} func1('George', 1982, 'USA'); Output:

Args: object

typeof func2: function

typeof variable: undefined

Args: [Arguments] { '0': 'George', '1': 1982, '2': 'USA' }

variable: undefined

function assignment: undefined

USA // With let/const ES6 function func1(...args) {

console.log('Args:', typeof args); console.log('typeof func2:', typeof func2); console.log('typeof variable:', typeof person); console.log('Args:', args); console.log('variable:', person); console.log('function assignment:', getName); let person = 'Paul';

const getName = _getName(); function func2() {

console.log('USA');

} func2();

} function _getName() {

return 'Steve';

} func1('George', 1982, 'USA'); Output:

Args: object

typeof func2: function

ReferenceError: Cannot access 'person' before initialization

The answer to this error lies in the ECMAScript specification.

let and const declarations define variables that are scoped to the running execution context's LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable's LexicalBinding is evaluated — ECMAScript

In simple words the lexically declared variables stay uninitialised. This means that a ReferenceError exception is thrown when you try to access it. It will only get initialised when the let/const statement is evaluated, everything before (above) that is called the temporal dead zone.

If you find this article helpful and enjoyed it, feel free to share it with friends and colleagues.

Do you have any questions, suggestions or would like to reach to me? Drop me a message on LinkedIN or comment below.

I am also available on twitter via the handle @zargarmuneer90.

Below are some good resources that i have followed while writing this article.