JavaScript

JavaScript – Execution Contexts in Detail: Creation, Execution Phases and Hoisting

MacBook on table near mug

As mentioned in the previous note, we can associate an execution context with an object: execution context object.

This object has three properties:
(Recap: properties are variables stored in objects)

  • Variable Object(VO): a special object contains  function arguments/ parameters, inner variable, and function declarations.
  • Scope chain: contains the current variable object as well as the variable objects of all its parents.
  • “this” variable

 


How is the execution context actually created?

When a function is called, the execution context is put on top of the execution stack, this happens in two phases.

  1. Creation Phase
  • Creation of the Variable Object(VO)
  • Creation of the scope chain
  • Determine value of the ‘this’ variable. (the ‘this’ variable is determined and set)

So basically, the three properties of the execution context object are defined.

Then in the execution phase, the code in the function that generated the current execution context is ran line by line. And all the variable are defined. If it’s the global context, then it’s the global code that is executed.


Variable Object (VO)

  • In the creation of the variable object, the argument object is created, containing all the arguments that were passed into the function.
  • Code is scanned for function declarations: for each function, a property is created in the Variable Object, pointing to the function.
    -> this means, all the functions will be stored inside the Variable Object, even before the code start executing. This is important!!
  • Lastly, the code is scanned for variable declarations: for each variable, a property is created in the Variable Object, and set to undefined.
    The final two points are commonly referred to Hoisting.

Hoisting: functions and variables are hoisted in JavaScript which means that they are available before the execution phase even starts.

However, they are hoisted in different ways though, the difference between functions and variables is that functions are actually already defined before the execution starts while variables are set to undefined.
And will only be defined in the execution phase.

The execution phase takes place right after the creation phase.

Recap: each execution context has an object which stores many important data that the functions will use while it’s running, and this takes place even before the code is executed.

 


Hoisting for Functions

Let’s write some simple functions.

function calculateAge(year){
  console.log(2018 - year);
}

calculateAge(2000);
//16

We’ve been declaring and calling functions like this, however, there exists another ways.

calculateAge(2000);

function calculateAge(year){
  console.log(2018 - year);
}

//16

This is actually Hoisting.

In the creation phase of the execution context, which in this case is the global execution context, the function declaration calculateAge is stored in the Variable Object and even before the code is executed.

This is why when we then enter the execution phase, the calculateAge() function is already ready for us to use. So that’s why we don’t need to first declare and then use it but we can first use it and only later in our code, declare it.

This only works for function declarations.

Remember Function expressions?

  1. declare a variable
  2. assign the function to it
var calRetirement = function(year) {
  console.log(65 - (2018 - year));
}

calRetirement(2000);
//47 yrs left for retirement

What will happen if we call the function before the function expression?

calRetirement(2000);

var calRetirement = function(year) {
  console.log(65 - (2018 - year));
}
//Uncaught TypeError: calRetirement is not a function

This is because hoisting only works for function declarations.


Hoisting for Variables

var age = 23;
console.log(age);

//23

What will happen if we use the variable before declaring it ?

console.log(age);
var age = 23;

//undefined

This is exactly how hoisting works with variables.
In the creation phase of the variable object, the code is scanned for variable declarations and then the variable is then set to undefined.

console.log(age);
// Uncaught ReferenceError: age is not defined

In this case, JavaScript does not even know this variable.

But in the case below, JavaScript knows that there will be an age variable, simply don’t have the value yet. And that’s also the reason why it is defined as undefined. (Variable does not have a value yet will always have a data type undefined)

console.log(age);
var age = 23;

//undefined

One more example:

console.log(age);
var age = 23;

function foo() {
  var age = 60;
  console.log(age);
}

foo();
console.log(age);

//
undefined
60
23

Why would this happen?

var age = 23;

The age variable is stored in the global execution context object, (to be more precise: is stored in the variable object of the global execution context object)

So this variable is declared in the global execution context object.

The foo function gets its own execution context object in which we can also store an age variable in the variable object with the same name as there are completely two different variables.

function foo() {
  var age = 60;
  console.log(age);
}

the age variable above is defined in the variable object of the execution context object of the function foo(), while

var age = 23;

is defined in the variable object of the global execution context object.

Each execution context object gets its own variable object so we have two different variables and when we print it to the console, the results are different.

 


Please note that this is my study notes that I took while taking the complete guide to JavaScript course on Udemy, if you are interested in understanding the language better, I highly recommend you to purchase the course 🙂 !

Standard

Leave a comment