top of page

How to understand Classes in Javascript?

Understanding why classes needed?
Program = Data + Instructions on data

Grouping of data --> structures --> C/C++.

Grouping of instructions --> functional programming.

Grouping of functions --> Classes --> Object Oriented Programming.


This is an idea of Encapsulation - Combination of data and functionalities.

We know that Javascript already has a data type called Objects.

Object can store string,number,arrays and functions.Please, functions inside objects are called methods.

Let's create an object,

There are three different ways to create an object,

First method

 let person1 = {
  name:'John',
  score: 0,
  incrementScore: function() {
   person1.score++
  }
 }
 person1.incrementScore();
 console.log(person1); 
 // {name:'John',score:1,incrementScore:function definition}

Let's talk another way to create object.

let person1 = {};

person1.name = 'John';
person1.score = 0;
person1.incrementScore = function() {
   person1.score++
  }

Another one,

 let person1 = Object.create(null); // always return empty object

person1.name = 'John';
person1.score = 0;
person1.incrementScore = function() {
   person1.score++
  }

We know that function creates execution context, and it has its memory.If the data is not available,it goes to outer scope.

Above methods are directly creating objects individually.

What if we want create for another persons like person1,person2,person3,etc.

It's inefficient declaring everytime for new person,right?


So we will pack set of instruction in to some function and it gives out object as output.

function personCreator(name,score) {
    let person = {};
    person.name = name;
    person.score = score;
    person.incrementScore = function() {
          person.score++
  }
  return person
  }
  
  let person1 = personCreator('John',0)
  let person2 = personCreator('Resse',0)
  let person3 = personCreator('Finch',0)
  
  person1.incrementScore();  
  person2.incrementScore();
  person3.incrementScore();
  

What happens here?

Global Execution context is created.It is pushed to call stack.

person1 is calling personCreator with arguments - John and 0.

Hence new Local Exceution context is created for person1 with parameters John and 0.

Inside the LEC , person is initialized to empty object {}.

The, we add name and age property to the empty object.

Atlast, we add an method(function inside object) called incrementScore that sores function definition.

Same happens for person2,person3.

Whenever we call person1.incrementScore(), new execution is created everytime on the call stack.
Same for person2/person3.incrementScore()

Everytime new object is created through the personCreator function, we get another copy of object and hence incrementScore() method.


So memory taken up every new object is proportional to number of persons created.Think of million persons, and hence scalability concerning memory is not efficient.


Yes! Jacascript has solution to this.

What if we can permanently attach the method/function(incrementCount) to the personCreator function.


We will see that now.

function personCreator(name,score) {
    // Use Object.create() with attaching function as arguments
    let person = Object.create(attachingFunction);
    person.name = name;
    person.score = score;
  return person
  }
 
 // it is an object
 const attachingObject = {
      incrementScore:function() {
       this.score++
  }
  }
  
  let person1 = personCreator('John',0)
  let person2 = personCreator('Resse',0)
  
  
Important: Please do read this.

Whenever a Object is created, there will be hidden property __proto__.This is called 'dunder proto.'

'dunder proto' is an object.

If dunder proto is an object , it can have properties and values.

It is like this,not 100% accurate -> but think of this as a mental model

person1 = {
  name:'John',
  score:0,
  __proto__: {
    incrementScore:function() {
       this.score++
    }
  }
}

So when the property/method use search is not inside person1 object,it will look inside whether it is available in 'dunder proto.'

This is Javascript property, and make sure that you understand it.


Why do we need 'this' keyword?

Note:'this' keyword is the most confusing part, and it depends on our scenario with javascript.


Just remember, 'this' in this scenario always refer to what ever sits left to dot operator.


  let person1 = personCreator('John',0)
  let person2 = personCreator('Resse',0)
  person1.incrementScore();
  person2.incrementScore();

So this refers to person1 and person2.

  • No matter how many objects you create, there will be one attaching function.

  • Think of attaching object as some space, and we can use it whenever we want to.

  • It needs to remember who uses it, so we must tell attaching object using "this" keyoword.

  • So if person1 uses it, 'this' will point to person1 inside attaching object, similarly, for person2,person3,etc.



Problem with the above approach is

We need to write everytime "Object.create()" add pass in parameter that will be "dunder proto."

We need to return the object in the Object creator function.

function personCreator(name,score) {
    // Use Object.create() with attaching function as arguments
    let person = Object.create(attachingFunction);
    person.name = name;
    person.score = score;
  return person
  }

We need to work on the function.

Note:

  • Object has "dunder property."

  • In javascript, all data types are objects.e.g., -> Array,Objects and Functions too.

  • Yes! Functions are objects too.

  • So all have "dunder property," and __proto__ will be there for functions too.

  • In addition to __proto__,function has unique property called prototype.

  • So __proto__ and prototype is different.

  • Prototype is only available in functions.

  • Prototype points to an object.

Please read the above points before proceeding and try to make it as simple as possible.


So any function can be viewed as

Let's refactor the code:



function personCreator(name,score) {
    this.name = name;
    this.score = score;
}
    
//accessing prototype by thinking function as object
personCreator.prototype.incrementScore = function() {
    this.score++    
}
    
// creating object using new keyword
const person1 = new personCreator('John',0)

Introducing "new" keyword:

We will understand through what it does,

1) It automatically creates a new object.

2) It automatically assigns 'this' to the new object.

3) We know every object has "dunder property". It attaches "dunder" to "prototype" object of function.

4) It automatically return the new object

Read the above 4 points over and over until it makes sense.Connect to the previous and see what it automates.


So new = new { } + attach 'this' to new { } + __proto__ and fucntion.prototype connection + return new { }
function personCreator(name,score) {
    this.name = name;
    this.score = score;
}
    
//accessing prototype by thinking function as object
personCreator.prototype.incrementScore = function() {
    this.score++    
}
    
// creating object using new keyword
const person1 = new personCreator('John',0);
person1.incrementScore();

Think of some one who comes OOP languages like C++,Java,etc.The above code doesn't make any sense to them syntactically.

JS introduced class keyword as syntactic sugar.

Syntatic sugar --> Just syntax change, but not how it works under the hood.

Code using Class syntax:


class personCreator {
    constructor(name,score) {
        this.name = name;
        this.score = score;
    }
    incrementScore() {
        this.score++
    }
}

const person1 = new personCreator('John',0)
person1.incrementScore();

Note: This is just syntax change, but it uses prototype chaining under the hood.


Recent Posts

See All

As there are many programming languages, there are many programming paradigms. Programming paradigm = style of programming = set of guidelines to solve the problem. So, many programming languages evol

bottom of page