Two Superpowers of advanced JS

Parakh Srivastava
5 min readAug 27, 2022

--

Introduction:

In this article, we will be looking at two of the most important and powerful concepts in advanced javascript that every JS developer should know about. These are quite unique powers that JS provide its developers as they are not available in all languages (although nowadays many programming languages are trying to implement them in the coming future). Once you get to understand these, it will evolve you as a JS programmer. These superpowers are CLOSURES and PROTOTYPES.

PREREQUISITES: A few topics that you should be good at before going through this tutorial are Higher Order Functions, Lexical Scoping, Functions, and Objects.

Closures:

Closures are the combination of Lexical Scoping & Functions. Lexical scoping means that the JS engine knows (before we run our program) what variables each function has access to. Functions, as we all know, is First Class Citizen (we treat functions similar to variables in other programming languages) in JS. From here we derive that…

Closures allow functions to access variables from an enclosing scope or an environment even after it leaves the scope in which the variable was declared.

Let’s see an example where how the JS should have worked if there were no closures existing, in this way we will be able to appreciate them on another level.

function fun1() {
let a = 'father';
return function fun2() {
let b = 'son';
console.log(`${a} -- ${b}`);
}
}
const fun1_result = fun1();fun1_result();
// Output: undefined -- son

If you are new to JS or new to any programming language, this would seem a genuine output to you, and would be confused that why even closures are there, as we are getting what this snippet should return. But no, here comes CLOSURES into the picture. Closures will be allowing inner functions to have access to variables of outer functions, to avoid the above situation. Thus, in JS, we will not be getting the output as shown above, but rather we will get → father -- son as an output.

Why Superpower?

At the very beginning of the article I mentioned closure as a superpower for JS developers, but why? Here we will look into the main reason for it being the same.

Suppose, there is an API that returns an object of each product details. Then we extract all product names from them and store them in an array. In this case, we will not expect to change products very frequently, thus this API will be getting called only once. Now, we have to find the product at the particular index of an array. Let us look at how we can approach this…

function getProduct(index){
const products = new Array(10000).fill('dummyProduct')
console.log('created array of 10000 products');
return products[index];
}
getProduct(500);
getProduct(1000);
getProduct(1500);

In the above code, we are having getProduct() which will create an array of 10000 products every time this method is called. So if we want to have products at 500th, 1000th, and 1500th indices, then every time a new array of 10000 products will get created and created an array of 10000 products will get logged three times.

To resolve this issue, CLOSURES superpower will come into play. Let’s see how…

function getProduct(){
const products = new Array(10000).fill('dummyProduct')
console.log('created array of 10000 products');
return function(index){
return products[index];
};
}
const getProductAtIndex = getProduct();getProductAtIndex(500);
getProductAtIndex(1000);
getProductAtIndex(1500);

Now, with the above code, our products array with 10000 elements will get created only once and our problem of it getting created again and again is resolved. I hope this example has made you understand the power of closures.

Let’s move on to the next superpower that JS gives its developers- PROTOTYPES

Prototypes:

Now it’s time to learn prototypes in JS and more specifically prototypal inheritance. This part of the tutorial can seem a bit overwhelming if you are getting introduced to prototypal inheritance for the first time. So, it’s advised to revisit the tutorial as it will help us in understanding OOP with respect to JS.

Javascript uses prototypal inheritance, i.e. objects will get access to properties and methods of other objects. For instance- Object is being inherited by Functions and Arrays, this means that Array and Function will get access to properties and methods of Object.

Prototypal Inheritance — 1

Practical Explanations:

const arr = [1,2,3];
arr.__proto__
arr.toString();

In the above code, we are creating arr which is a type of Array, so when we do arr.__proto__ it will return us an array of all the properties that it will have to deal with different types of tasks (which is in turn inherited from Object). For example- the toString() method is available because of Array but not because of arr that we created. Let’s see that diagrammatically…

Prototypal Inheritance — 2

Thus, to get the Object’s properties and methods, we can again use __proto__ with the above code, like this…

const arr = [];
arr.__proto__.__proto__

Functions work in a very similar manner. Every function is an Object in JS and thus, it also inherits properties and methods from an Object.

Practical Example:

Suppose, we have objects of two types of cars- ordinary and supermodel. Obviously, a supermodel car will be having some properties and methods that will not be a part of an ordinary car object. For instance:

const supermodel = {
name: 'mercedes',
autoGear: true,
speed: '400km/h'
};
const ordinary = {
name: 'maruti',
speed: '150km/h'
};
console.log(ordinary.autoGear)
// throws an error, as autoGear is not in ordinary

Now, if we want the ordinary object to have all the properties of a supermodel object, then __proto__ will become handy, let’s see…

const supermodel = {
name: 'mercedes',
autoGear: true,
speed: '400km/h'
};
const ordinary = {
name: 'maruti',
speed: '150km/h'
};
ordinary.__proto__ = supermodel;console.log(ordinary.autoGear)
// true
console.log(ordinary.speed)
// 150km/h

__proto__ will take the reference of all the properties (note: I wrote reference, as it doesn’t copy) and embed it into the ordinary object. As a next step, it will check if any of the properties are already present in the same, it will overwrite them with ordinary object’s values.

Using prototypes, we avoid repeating ourselves, making memory more efficient to use.

Conclusion:

In this article, we have learned about Closures and Prototypes, and how they give superpowers to JS developers. Also using these, we can now dive deep into different programming paradigms that JS supports, and we will be able to evolve more as a developer.

I hope you have enjoyed the article. Your valuable suggestions are always welcome. Happy Learning!!!

--

--