Execution context in JS

Image for post
Image for post

📄 Table of Contents

  • What is the Execution Context & Stack in JavaScript?
  • Hoisting
  • HTTP Caching — Part I

Execution context, Scope chain and JavaScript internals

In this section, we will discuss what is execution context and scope chain in JavaScript. We will also check the internal working of JavaScript step by step. Understanding these concepts will not only help in understanding the JavaScript internals but also other concepts like hoisting and closure.

Execution context (EC) is defined as the environment in which the JavaScript code is executed. By environment, I mean the value of this, variables, objects, and functions JavaScript code has access to at a particular time.

Execution context stack (ECS): Execution context stack is a stack (LIFO) data structure, i.e. last in first out data structure, to store all the execution stacks created during the life cycle of the script.

Execution context in JavaScript is of 3 types as:

  1. Global execution context (GEC): This is the default execution context in which JS code start its execution when the file first loads in the browser. All of the global code i.e. code which is not inside any function or object is executed inside the global execution context. GEC cannot be more than one because only one global environment is possible for JS code execution as the JS engine is single threaded.
  2. Functional execution context (FEC): Functional execution context is defined as the context created by the JS engine whenever it finds any function call. Each function has its own execution context. It can be more than one. Functional execution context has access to all the code of the global execution context though vice versa is not applicable. While executing the global execution context code, if JS engine finds a function call, it creates a new functional execution context for that function. In the browser context, if the code is executing in strict mode value of this is undefined else it is window object in the function execution context.
  3. Eval: Execution context inside eval function.

Global execution context is present by default in execution context stack and it is at the bottom of the stack. While executing the global execution context code, if JS engines find a function call, it creates a functional execution context for that function and pushes it on top of the execution context stack. JS engine executes the function whose execution context is at the top of the execution context stack. Once all the code of the function is executed, JS engines pop out that function’s execution context and start’s executing the function which is below it.

Let’s understand this with the help of an example:

Image for post
Image for post

As soon as the above code loads into the browser, JS engine pushes the global execution context in the execution context stack. When functionA is called from global execution context, JS engine pushes functionA execution context in the execution context stack and starts executing functionA.

When functionB is called from functionA execution context, JS engine pushes functionB execution context in the execution context stack. Once all the code of functionB gets executed, JS engine pops out functionB execution context. After this, as functionA execution context is on top of the execution context stack, JS engine starts executing the remaining code of functionA.

Once all the code from functionA gets executed, JS engine pops out functionA execution context from execution context stack and starts executing remaining code from the global execution context.

When all the code is executed JS engine pops out the global execution context and execution of JavaScript ends.

So far we have discussed how the JavaScript engine handles the execution context. Now, we will see how it creates the execution context.

Understanding “this” binding in a normal Javascript function and ES6 Arrow function + execution Context

Arrow Function is the syntactic sugar which makes the code lot clear and concise. Arrow Function is one of the more popular features of ES6 and has several benefits. They even allow implicit returns when there is no body block. But we are here to talk about the binding of arrow functions!

Arrow syntax automatically binds this to the surrounding code’s context.

Image for post
Image for post

Here, the Person function is a constructor function. We are creating an object person1 by the new keyword.

var person1 = new Person('Joey Smith', 25);
  1. When this line is executed the constructor function Person following the new keyword is invoked, which sets the attributes of the empty object that is newly created using this.property_name which includes personName, age, and function getDetails. This constructor implicitly returns an object which is stored in the person1 variable.
  2. Then we can invoke the member function getDetails of the person1 object to console the details of the person by the execution of the following line of code.
person1.getDetails()

3. The getDetails have a setTimeout which will execute the function passed in it after the specified time (time is passed as the second argument to the setTimeout function). The callback passed in setTimeout is the normal function in which this is being referred.

When the above code is executed the following output is generated:

Name: undefined, Age: undefined

The name and age both got undefined. Oopsie!! That’s not what you must have expected.

Why is that?
The reason for the undesired output is that in normal functions this keyword represents the object that has called the function. When our function getDetails is normally invoked this keyword represents the global object that is the window object in our case and there is no variable with the name personName or age in the global object, due to which both of these are undefined.

But what’s happening in the execution stack?

First of all the Global Execution Context enters the Execution Stack which has a constructor function Person and person1 object in its variable environment. The Person object is created via new keyword by the steps explained above and then stored in the person.

Image for post
Image for post

Execution Stack

After that, the Global Execution Context invokes the getDetails function which is a member function of the person1 object. When the getDetails function is invoked, its execution context is created and pushed onto the Execution Stack.

Image for post
Image for post
Execution Stack

The getDetails function has the setTimeout which has a callback that will enter the Callback Queue (just assume its a storage where callbacks are put ) and will be executed once our execution context other than global Execution Context is popped out from the Execution Context.

Image for post
Image for post

The left side is execution Context and on the right side is the setTimeout function waiting for the specified time to pass

When the stack gets empty (except global Execution Context) the callback will be executed and a new Execution Context will be made. i.e. the callback is invoked normally and this keyword in it represents the Global Context.

Image for post
Image for post
Execution Stack

In the case of a normally invoked function, this keyword represents the global Context and when personName and age variable is not found in the Global Context it gives undefined.

So this is our problem that while normal function invocation the this represents the object that has called the function, not the surrounding context itself.

How to solve this?

All the functions in JavaScript have access to some special methods on their own and bind(), call() and apply() are few of them. One the solution is using these bind(), call() or apply(). By using these methods we can control, what this ends up representing.

Therefore by using these methods we can bind the Person to the callback function and then our problem will be solved. Following is the example of using a bind method on the callback function and binding it to the Person.

Image for post
Image for post

Similarly, we can use apply and call method.

But why going through so much trouble when the problem can be solved just by syntax change.

In such a scenario, Arrow Function comes to rescue with its so easy syntax.

If we use the arrow function as callback instead of the normal function our problem will be gone. Let’s see the code.

Image for post
Image for post

We get the following output on executing the code.

Name: Chandler, Age: 25

Basically in the Arrow function, this always represents the object in which the arrow function is defined. Arrow syntax automatically binds this to the surrounding code’s context under the hood.

In the Arrow function, it is not dependent on how they are invoked but it closes on the surrounding context.

Hoisting

In JavaScript, there are multiple ways to declare a function. One way is to declare it with the function keyword. The other way is to declare it as an arrow function.

In fact, there are two ways to declare a function with the function keyword. One way is using function declarations, which are also called function statements, and the other is to use function expressions.

In JavaScript, functions are first-class, which means that they’re objects we can define on the fly.

A function declaration is stored in memory prior to executing the program. This means we can reference it anywhere in our code, even before it’s declared. Storing a variable in memory prior to executing the program is called “hoisting” in JavaScript.

For example, if we write the following:

console.log(foo());function foo() {
return 'foo'
}
console.log(foo());

We get foo logged from both function calls.

Unless they’re function declarations or statements, function expressions aren’t stored in memory before the program runs. The function is defined in run-time, so we can only reference them after they’re declared.

For example, if write the follwing:

console.log(foo());const foo = function() {
return 'foo'
};
console.log(foo());

We’ll get the following error: Uncaught ReferenceError: Cannot access ‘foo’ before initialization’.

In the code above, we have the variable declaration when the program initially runs, but we don’t have the function assigned to it yet, so we can’t access it. Also, anything defined with the let , or const keywords can’t be used with those variables or constants before it’s defined, which also prevents it from being run.

HTTP Caching

You might have heard about caching. We have several types of caching database caching, CDN caching, DNS caching etc.. However, web caching or HTTP caching which occurs at application level is what we are going to discuss in this article. I am going to cover key terms and definitions in this article and their actual implementations, use cases, advantages and disadvantages in the upcoming articles.

Caching, in general is a mechanism to prevent fetching the same resource, if unchanged again and again costing data and affecting performance. The retrieval of previously fetched resource can be prevented by storing the data locally and verifying the presence of a resource locally before making any other request.

This can be achieved by passing some special cache directives in the response headers of an HTTP request.

Cache-control: This is the caching directive that is used to specify who can cache a resource and how long one can cache it. This takes the values

  • max-age: This takes the value of the time period for which the resource is valid and can be reused from the cache.
  • public or private: “public” lets the resource to be cached even if it has HTTP authentication associated with it. A resource with “private” in the cache-control directive prevents intermediate caching and allows only the end user to cache it.
  • no-cache or no-store: “no-cache”means the client must validate the freshness of a resource even though the resource is cached. “no-store” disallows the browser and all intermediate caches from storing any response.

Experience with Front-end Technologies and MERN / MEAN Stack. Working on all Major UI Frameworks like React, Angular.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store