Advanced JavaScript: Chapter 2 - How javascript works?

Advanced JavaScript: Chapter 2 - How javascript works?

Understanding the internal workings of javascript becomes very important to become a good JavaScript developer.

In this article, we will understand the execution context. A good understanding of this concept will make it easier to understand crucial concepts like Hoisting, Scope chaining, closures, etc.

After reading this article you will have enough knowledge to understand the hard parts of javascript and grasp the core concepts easily. So, let's begin.

What happens on executing a javascript code?

When we execute a javascript code the syntax parser parses the code and then the compiler translates it to computer instructions(low-level language).

In JavaScript, the compiler is written in a way that it cares about where we have written the codes and based on that it assigns the memory.

In our previous blog, we explored the concept of scope chaining, which directly determines where a variable is defined and consequently, whether it can be accessed or not.

What is an execution context?

An execution context is basically an environment that gets created when a fragment of JavaScript code runs. It is created to handle all the transformations and execution of the code. It contains the currently running code and everything that helps in running that code.

There are basically two types of execution contexts:

  1. Global execution context: It gets created at the start of the execution of the javascript code and it remains till the code is running.
  2. Local execution context: It gets created for every function that runs and gets destroyed when the function exits its execution ( that is after it returns some value)

Phases of execution context

There are two phases of an execution context:

  1. Creation phase: As soon as execution is created it checks all the variables and functions defined inside its context (or scope) and it declares each variable and function beforehand.
  2. Execution phase: After the creation phase the execution context has every information that is needed to start the execution of the code and then it reads every line of code one by one and executes it.Let's understand the creation and execution of execution context by an example:

function greet(){
    console.log("Welcome to the blog!");
    var surname_in_greet = "Mishra";
    
    return surname_in_greet;
}

var name = "Abhinandan";
var surname = greet();

console.log(name+" ", surname)        

  • As soon as this javascript code runs, a Global Execution Context (GEC) gets created.

Global Execution Context

  • The functions are stored as it is and variables are assigned undefined as a value.
  • After the execution of the below line of code ( line marked using indicator runs), the name variables get assigned "Abhinandan" as a value

  • The global execution context looks like this now:

name is assigned a value

  • Now, greet() function is invoked and a local execution context for greet() gets created.

Local Execution Context - greet()

  • In the execution phase of the execution context of the greet function, the first line gets executed, and "Welcome to the blog!" is printed in the console.
  • On the next line of execution, the variable surname_in_greet is assigned "Mishra" as a value and surname_in_greet is then assigned as a return value for the greet().

return value is the value that will be returned by the function.
Local Execution Context - greet()

  • As soon as the greet() returns a value, its execution context gets destroyed and the javascript engine goes back to the point where greet() was invoked and then the returned value of greet() is assigned to the variable surname.

Global Execution Contest after greet()

  • At the end, the last line of code is a console statement that will print "Abhinandan Mishra" as an output.

This is how the creation and execution of execution context works in the javascript.

Hoisting

Hoisting is referred to as the process in which the interpreter appears to move the declarations of functions and variables to the top of their scope prior to the execution of the code.

Now as we understand the creation phase of an execution context we can easily understand the hoisting.

Let's understand this by the previous example but with some small changes.

name = "Abhinandan";
var surname = greet();

function greet(){
    console.log("Welcome to the blog!");
    var surname_in_greet = "Mishra";
    
    return surname_in_greet;
}

var name;

console.log(name, surname)        

  • In the above code, I have moved the name and surname variables to the top and greet() is getting invoked before it's declarations.
  • Since we know that in the creation phase, the variables and functions are declared prior to the execution, and hence in the first line even if we have not written the var keyword it still understands that there's a name variable present and here a value is being assigned.

That is all these codes written below behave the same in javascript:-

Code1:

var name = "Abhinandan"         

Code2:

var name;
name = "Abhinandan";        

Code3:

name = "Abhinandan"    
// because name is already declared in the creation phase
var name;        

That's what hoisting is, that is the function and variables declarations are on the top of their scope ( obviously because of the creation phase of the execution context occurring before the execution phase of the execution context).

Whether let and const are hoisted or not?

So, one question that comes to mind of every person who's learning JavaScript is whether the let and const are hoisted or not.

Now, your question should be why this question arises.

The answer is that if we access the let and const declared variables before their declarations, the javascript engine throws an error.

Because let and const were introduced in ES6, the motive was to declare the block-scoped variables that can't be accessed out of the block. Block scoped variables are also hoisted but they are in the temporal dead zone till they get defined.

A variable in the temporal dead zone means that it has been declared in the creation phase of execution context but it is not accessible to the outer environment.

Once the block scoped variable gets declared it is moved out of the temporal dead zone and it becomes accessible.

Let's understand this temporal dead zone by the following example-

// block starts here
{
  // name's TDZ starts here (at the beginning of this block’s local scope)

  // name's TDZ continues here
  // name's TDZ continues here
  // name's TDZ continues here
  // name's TDZ continues here

  let name = "Abhinandan Mishra"; // name's TDZ ends here

  // name’s TDZ does not exist here
  // name’s TDZ does not exist here
}
// block ends here        

So, the answer is that all the variables and functions are hoisted but the variables and functions declared with let and const are inaccessible before their definition.

That's it for this article, hope you have learned something new or brushed up your knowledge.

Thank you for reading the article.

Manish Agrahari

?Aspiring Software Engineer ?Golang/Java && React ?Ex- Software Engineer Intern at EMSEC ?Ex- SDE [email protected] ?FullStack Developer ?ML/ AI Enthusiast ?Competitive Coder ?1700+ at LeetCode ?3 ?? at Codechef

1 年

Loved it, awesome explanation Abhinandan sir ?? ?? ??

Niranjan Singh

AASE @ Accenture

1 年

Loved this article ????... Nice way to explain things...Smoother flow which makes the topics crystal clear ??... Thanks for sharing ??

Nidhi Pal

Specialist Programmer @ Infosys | JavaScript, Angular, .NET Core | Full Stack Developer |

1 年

Well explained ??

Ekansh Saxena

SDE - I @Expedia Group | Ex- SDE - Intern @Juspay | Siemens Scholar - Batch 07 | ICPC Regionalist '21

1 年

Again an insightful article, thanks for sharing ?

要查看或添加评论,请登录

Abhinandan Mishra的更多文章

社区洞察

其他会员也浏览了