Swastik Yadav

S Y

Navigate back to the homepage

Intro to object oriented programming in JavaScript

Swastik Yadav
July 23rd, 2021 · 3 min read

Hello Everyone,

In this post we will explore the object oriented programming paradigm in JavaScript. OOP is a paradigm where everything is managed with objects.

There are four ways to work with objects in JavaScript:

  • Factory way of creating objects.
  • Prototypal way of creating objects.
  • Pseudo Classical pattern of creating objects.
  • Classes

The best way to work with objects are classes. We will learn exactly how classes works. Let’s explore each method one by one.

Factory way of creating objects

Let’s say we need to create multiple students object. With factory way, we don’t manually need to create objects for all of them. We create a constructor function.

1function creteStudent(name, batch, marks, maxMarks) {
2 let obj = {};
3 obj.name = name;
4 obj.batch = batch;
5 obj.marks = marks;
6 obj.maxMarks = maxMarks;
7 obj.percentage = function() {
8 return `${(marks*100)/maxMarks}%`;
9 };
10
11 return obj;
12}

Next whenever we need to create a student, we just have to call the above function.

1let student1 = createStudent("Swastik", 9, 95, 100);
2let student2 = createStudent("Rahul", 8, 90, 100);
3
4student1.percentage() // 95%

This was the factory way of creating objects.

Prototypal way of creating objects

When a property is not found in an object, it looks for it down in the prototypal chain. This is the prototypal nature of object.

prototypal-chain

Now let’s create object the prototypal way.

  1. Create object using Object.create().
  2. Make sure to use this in the method.
  3. Make sure to return object.
1let studentMethod = {
2 percentage: function() {
3 return `${this.marks*100 / this.maxMarks}%`;
4 }
5}
6
7function createStudent(name, batch, marks, maxMarks) {
8 let obj = Object.create(studentMethod);
9 obj.name = name;
10 obj.batch = batch;
11 obj.marks = marks;
12 obj.maxMarks = maxMarks;
13
14 return obj;
15}
16
17let student1 = createStudent("Swastik", 9, 99, 100);
18student1.percentage(); // 99%

Object.create takes an object as parameter and puts that parameter into dunder-proto. For example in the above code snippet percentage method is added in dunder proto, it is not in the main object.

Pseudo Classical pattern of creating objects

Pseudo classical pattern uses the new keyword with constructor function to create objects. The new keyword does 3 things.

  1. Creates a new object implicitly, named this.
  2. Puts the new object (this) in function prototype.
  3. Implicitly returns obj (this).

When we use new keyword, methods from prototype goes to dunder-proto.

  1. this = {}
  2. this.proto = createStudent.prototype
  3. return obj (this)

For instance:

1function CreateStudent(name, batch, marks, maxMarks) {
2 this.name = name;
3 this.batch = batch;
4 this.marks = marks;
5 this.maxMarks = maxMarks;
6}
7
8CreateStudent.prototype = {
9 percentage: function() {
10 return `${this.marks*100 / this.maxMarks}%`;
11 }
12}
13
14let student1 = new CreateStudent("Swastik", 9, 100, 100);
15student1.percentage(); // 100%

The new keyword implicitly creates the object, sets the method to dunder-proto, and implicitly returns the object.

Classes

Classes are a syntactic sugar to create objects. In the last example we added the percentage method to CreateStudent.prototype manually. With classes all that is done automatically.

  • The new keyword calls the constructor and implicitly creates and returns the this object.
  • Classes accepts only methods (functions).
  • You will find the methods in the dunder-proto of the object.

For instace:

1class CreateStudent {
2 constructor(name, batch, marks, maxMarks) {
3 this.name = name;
4 this.batch = batch;
5 this.marks = marks;
6 this.maxMarks = maxMarks;
7 }
8
9 percentage() {
10 return `${this.marks*100 / this.maxMarks}%`;
11 }
12}
13
14let student1 = new CreateStudent("Swastik", 9, 89, 100);
15student1.percentage(); // 89%
16student1.percentage === CreateStudent.prototype.percentage; // true

So, that’s how we create objects with classes. Enumerable flag for class methods are by default set to false, because we don’t want methods in for…in loop result.

Class Inheritance

Class inheritance is a way to create new functionality on top of existing one. Let’s say we have an Animal class and a Rabbit class based on Animal class.

1// Animal Class
2class Animal {
3 constructor(name) {
4 this.speed = 0;
5 this.name = name;
6 }
7
8 run(speed) {
9 this.speed = speed;
10 alert(`${this.name} runs with speed ${this.speed}.`);
11 }
12
13 stop() {
14 this.speed = 0;
15 alert(`${this.name} stands still.`);
16 }
17}
18
19let animal = new Animal("My animal");
20
21// Rabbit Class
22class Rabbit extends Animal {
23 hide() {
24 alert(`${this.name} hides!`);
25 }
26}
27
28let rabbit = new Rabbit("White Rabbit");
29
30rabbit.run(5); // White Rabbit runs with speed 5.
31rabbit.hide(); // White Rabbit hides!

Rabbit class does not have run method but it can access it from Animal.prototype as we have extended Rabbit class.

class-extend

The Super keyword

The super keyword allows us to call parent method and constructor in our extended class.

  • super.method(…) calls a parent method.
  • super(…) calls parent constructor.

For instance:

1class Rabbit extends Animal {
2 constructor() {
3 super(); // calls the parent constructor
4 }
5
6 hide() {
7 alert(`${this.name} hides`);
8 }
9
10 stop() {
11 super.stop(); // calls stop method of parent
12 this.hide()
13 }
14}
15
16let rabbit = new Rabbit("White Rabbit");
17
18rabbit.run(5); // White Rabbit runs with speed 5.
19rabbit.stop(); // White Rabbit stands still. White Rabbit hides!

In the above code snippet, Rabbit class defines a stop method which calls the stop method of Animal with super.

The static method

We can also assign a method to the class itself, not to its “prototype”. Such methods are called static methods. They are prepended by static keyword.

1class User {
2 static staticMethod() {
3 console.log(this === User);
4 }
5}
6
7User.staticMethod(); // true

Static methods are used for functionality that belongs to the class “as a whole”. It does not relate to a concrete class instance.

Static properties and methods are inherited. For class B extends A the prototype of the class B itself points to A: B.[[Prototype]] = A. So if a field is not found in B, the search continues in A.

Private and protected properties and methods

  • Protected fields starts with _. Protected field should only be accessible from its class and classes inheriting from it. Protected field is not supported at the language level.
  • Private fields starts with #. Private field should only be accessibe from inside the class.
1class CoffeeMachine {
2 #waterAmount = 0;
3
4 set waterAmount(value) {
5 if (value < 0) {
6 value = 0;
7 }
8 this.#waterAmount = value;
9 }
10
11 get waterAmount() {
12 return this.#waterAmount;
13 }
14
15 constructor(power) {
16 this.power = power;
17 }
18}
19
20let coffeeMachine1 = new CoffeeMachine(100);
21coffeeMachine1.#waterAmount; // Error - Private method cannot be accessed outside of the class.
22coffeeMachine1.waterAmount; // 0;
23coffeeMachine1.waterAmount = -20;
24coffeeMachine1.waterAmount; // 0;

Private method #waterAmount is only accessible inside the class itself.

The this keyword

The this keyword refers to the object it belongs to. There are four rules to identify, where the this keyword is refering.

  1. fn() -> window
  2. obj.fn() -> this referes to obj. If any function is using this then this becomes the object at left of (.).
  3. bind, call, apply -> “this” value is specified.
  4. new keyword creates and returns this implicitly.

“this” changes at runtime.


That’s it for this post. I hope you found it helpful, if so, please do share and subscribe to my newsletter below or here.

Thank You!

More articles from Swastik Yadav

Working with modules in JavaScript

Introduction to modules in JavaScript and export / import.

July 16th, 2021 · 1 min read

Callback functions and closures in JavaScript

Learn what are Higher order functions, callback functions, and closures.

July 9th, 2021 · 1 min read

DiaryOfADev, Success stories of underdog developers.

Every week we share an underdog developer's story and a deep dive into a programming concept.

© 2021–2024 Swastik Yadav
Link to $https://github.com/SwastikyadavLink to $https://www.linkedin.com/in/swastikyadav/