DEV Community

Ehab Hussein
Ehab Hussein

Posted on • Edited on

OOP (Object-Oriented Programming) in JavaScript

Introduction to Object-Oriented Programming in JavaScript

Object-Oriented Programming (OOP) is a popular programming paradigm that helps organize and structure code by treating objects as the fundamental building blocks of a program. It provides a way to model real-world entities and their relationships, making code more modular, reusable, and easier to maintain. In this blog post, we will explore the basics of OOP in JavaScript, including prototype definition, prototypal inheritance, and the prototype chain.

In a normal object literal you would define keys and values:

const person = {
  id: "1",
  name: "John",
  age: 30,

  sayHello() {
    console.log(`Hello ${this.name}`);
  }
}
Enter fullscreen mode Exit fullscreen mode

without OOP you will repeat the same code over and over each time you want to define another person.

in OOP we can define the person as a model just once and then instantiate real objects from this model.
Ex: (This is not a valid code. just for demonstration)

// Person model
const Person = {
  id
  name
  age

  sayHello() {
    console.log(`Hello ${this.name}`);
  }
}

const john = new Person('1', 'John', 30);
const doe = new Person('2', 'Doe', 45);
Enter fullscreen mode Exit fullscreen mode

To create a model in javascript there are actually three different ways.

But we will take here the right one that allows you to understand it easily.

With constructor functions, you can create a model or a blueprint.
A constructor function is a special type of regular functions, it is used with the new keyword to create instances of a model. This is what makes a function to be a constructor function that constructs a model.

Great, let's define a constructor function to build our model from the previous example (Person):

const Person = function(id, name, age) {
  this.id = id;
  this.name = name;
  this.age = age;
}
Enter fullscreen mode Exit fullscreen mode

Since it is a regular function like any other function, we can leverage the function's arguments to assign values to the properties of each Person instance.
Here we have assigned each argument to its corresponding property.

This is great, but how can we create instances of this model?

Here the new keyword comes into play:

To create an object, we have to call the function with the 'new' keyword:
const john = new Person('1', 'John', 30)

Actually, when we call a function with the 'new' keyword there are 4 things happened:

  1. A new object is created.
  2. The function is called and 'this' will point to the newly created object.
  3. The prototype object of the constructor function will be linked to the object. (later)
  4. The function automatically returns the object.

console.log(john); // Person { id: '1', name: 'John', age: 30 }
Now, john's object is created and we can access its property like any other object:
console.log(john.name); // John

Now, let's talk about the third feature that 'new' keyword gave to us.

Every JavaScript object has a prototype, which serves as a blueprint for that object.
For our example, the prototype of john is Person.

What does it useful for?
Well, we can take advantage of this behavior by defining our methods in the prototype of john which is Person.prototype
and use it whenever an object needs to use it.
So the function in the prototype defined once. this approach is increasing the performance of our web app.

const Person = function(id, name, age) {
    this.id = id;
    this.name = name;
    this.age = age;
};

Person.prototype.sayHello = function() {
  return `Hello ${this.name}`;
};

const john = new Person('1', 'John', 30);
console.log(john.sayHello()) // Hello John;
console.log(john.__proto__); // prints the prototype of John: Person { sayHello: [Function] }
Enter fullscreen mode Exit fullscreen mode

Now we can access this method by any object of type Person. this approach is called prototypal inheritance, in which the objects is inheriting the methods from its prototype.

But never define a function inside the constructor function:

const Person = function(id, name, age) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.sayHello = function() {
    return `Hello ${this.name}`;
    }
};

const john = new Person('1', 'John', 30);
console.log(john.sayHello()) // Hello John;
console.log(john.__proto__); // {}
Enter fullscreen mode Exit fullscreen mode

With this approach, we are copying the function to each object created. Imagine we've created 1000 objects of type Person, this will define sayHello function for each object, which of course damaging our performance.

Prototype Chain
JavaScript uses a prototype chain to find properties and methods of an object. If a property or method is not found on an object, JavaScript looks up the prototype chain until it finds it.

For example, when we call john.sayHello(), JavaScript first checks if john has a sayHello method. If not, it looks for it in the Person prototype.

Conclusion
Understanding OOP and the prototype chain is essential for writing clean and efficient JavaScript code. By leveraging constructor functions and prototypes, we can create modular and reusable code that is easier to maintain.

Top comments (0)