🇪🇸

Este artículo solo está disponible en Inglés.

Unlocking the Power of Polymorphism in JavaScript: A Deep Dive

Polymorphism is a concept in object-oriented programming that allows objects of different types to be treated as objects of a common type. This allows for more flexible and reusable code, as well as a more intuitive way of thinking about objects and their interactions.

Overview

In JavaScript, polymorphism is implemented through the use of prototypes and prototypal inheritance. Every object in JavaScript has a prototype, which is another object that it inherits properties and methods from. This allows for the creation of a chain of prototypes, where an object can inherit from another object, which in turn inherits from another object, and so on.

This chain of prototypes is what enables polymorphism in JavaScript. For example, let’s say we have two different objects, a Dog and a Cat. Both of these objects have a method called “speak”, but the Dog’s “speak” method makes it bark, while the Cat’s “speak” method makes it meow.

If we create a new object called “Animal” that inherits from both the Dog and the Cat, we can now call the “speak” method on the Animals object, and it will automatically call the correct “speak” method based on the type of the object it is.

To implement polymorphism in JavaScript, we can use the “prototype” property of an object to set the prototype of another object. For example, we can set the prototype of the Dog object to be the Animals object, so that the Dog object inherits all of the properties and methods of the Animals object.

What exactly is Polymorphism in JS

JavaScript is a prototype-based language, which means that instead of using classes like in other object-oriented languages, it uses prototypes to create objects and define their behavior. This is what allows for polymorphism in JavaScript.

Polymorphism in JavaScript allows us to use the same method or property name on different objects, and have each object respond or behave differently. This is possible because JavaScript’s prototype-based inheritance allows objects to inherit properties and methods from other objects, and also allows those properties and methods to be overridden.

For example, let’s say we have a base object called “Animal” that has a method called “speak”. We can then create two other objects, a “Dog” object and a “Cat” object, that inherit from the “Animals” object. The “Dog” object can override the “speak” method to make the dog bark, while the “Cat” object can override the “speak” method to make the cat meow.

Now, if we have an array of these different animal objects, we can call the “speak” method on each of them and it will automatically call the correct method based on the type of the object.

In this example, polymorphism allows for code reuse, where we don’t have to write separate methods for each animal, and also allows for flexibility, where we can add new animals to our array and they will automatically have the “speak” method without having to add it manually.

Another example of polymorphism in JavaScript is using the same method name on different objects, but each object implements the method differently. This allows you to use the same method name on different objects, while still having the objects behave differently.

Implementing Polymorphism in JS

There are several ways to implement polymorphism in JavaScript, each with its benefits and drawbacks. These include:

  • function overloading,

  • method overriding, and

  • duck typing.

What is Function overloading?

It is a technique where a single function can have multiple signatures or ways it can be called. This allows the function to behave differently based on the number and types of arguments passed to it.

For example- let’s say we have a function called “calculate” that can be called with either one or two arguments. If it is called with one argument, it will return the square of that number, but if it is called with two arguments, it will return the product of those two numbers.

// In this example, the `calculate` function has two different signatures, one that takes one argument and one that takes two arguments. Depending on the number of arguments passed, the function will behave differently.

function calculate(a, b) {
  if (b === undefined) {
    return a * a;
  } else {
    return a * b;
  }
}
console.log(calculate(5)); // 25
console.log(calculate(5, 6)); // 30

What is Method overriding?

It is a technique where a child object can override a method that is defined in its parent object. This allows the child object to change the behavior of the method to better suit its own needs.

For example- let’s say we have a parent object called “Animals” that has a method called “speak”. We can then create a child object called “Dog” that inherits from the “Animals” object and overrides the “speak” method to make the dog bark.

//In this example, we have a base object called "Animals" that has a method called "speak". We then create two child objects called "Dog" and "Cat" that inherit from the "Animals" object and override the "speak" method to make the dog bark and the cat meow respectively.

let Animal = {
  speak: function() {
    console.log("Animals make different sounds");
  }
};

let Dog = Object.create(Animal);
Dog.speak = function() {
  console.log("Woof woof");
};

let Cat = Object.create(Animals);
Cat.speak = function() {
  console.log("Meow meow");
};

let dog = Object.create(Dog);
dog.speak(); // "Woof woof"
let cat = Object.create(Cat);
cat.speak(); // "Meow meow"

What is Duck typing?

It is a technique where an object is judged by its behavior rather than its type. This means that an object is considered to be of a certain type if it has the required properties or methods.

For example- let’s say we have an object called “Bird” that has a property called “canFly” and a method called “fly”. We can then create another object called “Plane” that also has the “canFly” property and the “fly” method. Even though “Plane” is not an instance of the “Bird” object, it is considered to be a “Bird” because it has the same properties and methods.

// In this example, we have two different objects, "Bird" and "Plane", that both have a property called "canFly" and a method called "fly". We then create a function called "fly" that checks if the object passed to it has the "canFly" property and the "fly" method. If it does, it calls the "fly" method on that object. Because both "Bird" and "Plane" objects have the required properties and methods, they are considered to be of the same "type" and the fly function works on both objects.

let Bird = {
  canFly: true,
  fly: function() { console.log("I'm flying"); }
};

let Plane = {
  canFly: true,
  fly: function() { console.log("I'm flying in the sky"); }
};

function fly(obj) {
  if (obj.canFly && obj.fly) {
    obj.fly();
  }
}

let sparrow = Bird;
let boeing = Plane;

fly(sparrow); // "I'm flying"
fly(boeing); // "I'm flying in the sky"

Polymorphism and Prototype chain

In JavaScript, objects are linked together through a prototype chain, which is a chain of prototypes where an object can inherit properties and methods from another object, which in turn inherits from another object, and so on. This chain of prototypes is what enables polymorphism in JavaScript.

For example- let’s say we have a base object called “Animals” that has a method called “speak”. We can then create a child object called “Dog” that inherits from the “Animals” object and overrides the “speak” method to make the dog bark.

Now, let’s say we create another child object called “Poodle” that also inherits from the “Animals” object, but it doesn’t override the “speak” method. The “Poodle” object will inherit the “speak” method from the “Animals” object, so it will also have the ability to speak, but since it hasn’t overridden the method, it will use the implementation provided by the “Animals” object.

This allows for a more intuitive way of thinking about objects and their interactions, as well as more flexible and reusable code. For example, if we want to add a new method or property to all “Animals” objects, we can simply add it to the “Animals” object, and all child objects that inherit from it will automatically have access to that new method or property.

Takeaway

In this article, we discussed the different ways to implement polymorphism in JavaScript, including function overloading, method overriding, and duck typing. We also explained how the prototype chain in JavaScript affects polymorphism and how polymorphism can be implemented and inherited through the prototype chain.

This post was not meant for beginners, but slowly I will post blogs on many methods I mentioned above and other things. Thank you for reading.

Share to your friends
Author avatar

Rahul