DEV Community

loading...
Cover image for Overriding methods in JavaScript using prototypes

Overriding methods in JavaScript using prototypes

Nuwan Karunarathna
I'm a passionate 'software engineering student' + 'freelance developer'
・3 min read

JavaScript is not considered as a fully object oriented programming language instead it is known as a object based programming language or a prototype based language. That means JavaScript supports some of object oriented concepts to some extent but not fully supported. Confusing right? Some may even argue that JavaScript has classes. Yes it has the class keyword introduced in ES2015 but it is considered as 'syntactical sugar'. Underneath it is still prototypes running the business. So in this article we are going to learn about how to override methods in JavaScript and what is happening underneath with prototypes.

Prototypes

First of all, lets have a little look into prototypes in JavaScript. A prototype has the same meaning as a parent class in OOP languages but at the same time it is different. In JavaScript, each and every object or function has a linked prototype. For example if we run the below snippet in a console we can see the prototype of a function.

function someFunction(){}
console.log(someFunction.prototype);
Enter fullscreen mode Exit fullscreen mode

Output:

{
    constructor: ƒ someFunction(),
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}
Enter fullscreen mode Exit fullscreen mode

The above output is the prototype of the function someFunction. In here you may notice a property called __proto__. This is the prototype of the someFunction's prototype. This is called as the chain of prototypes and it will go and go on until the __proto__ becomes null.

now let's create an instance of this someFunction and add some new properties to it.

let someOtherFunction = new someFunction();
someOtherFunction.someOthervalue = 'new value';
console.log(someOtherFunction);
Enter fullscreen mode Exit fullscreen mode

Output:

{
    someOtherValue: "new value",
    __proto__: {        
        constructor: ƒ doSomething(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Here we can see that adding a new property to the someOtherFunction did not affected the prototype of it but added a new property on top of it. This is the point we are going to utilize to override methods.

Override methods

Let's check the below snippet. In here lets use objects instead of functions.


let person  = {
  fName:'John', 
  lName:'Pillip',
  age: 23,
  getName: function(){
      return `${this.fName} ${this.lName}`
  },
  getAge: function(){
      return `${this.age} years`
  }
}

console.log(person.getName());
console.log(person.getAge());


// create an instance from the person object
let newPerson = Object.create(person);

// instead of a new property, let's add a function with the same name 
newPerson.getName = function(){
  return `${this.lName} ${this.fName}` 
}

console.log('');
console.log(newPerson.getName());
console.log(newPerson.getAge());


Enter fullscreen mode Exit fullscreen mode

Output:

"John Pillip"
"23 years"

"Pillip John"
"23 years"

Enter fullscreen mode Exit fullscreen mode

So let's breakdown what's happening. First we created a person object and the getName() ran the way we expected. Then we created a new instance of the person called newPerson. Here comes the interesting part, we add a function called getName() to the newPerson . Now when we ran the snippet, newPerson executed its own getName() function and override the getName() of person. Yay method overriding!. Okay but why that happened. Let's take a look at the newPerson.

{
    getName: ƒ (),
    __proto__: {
        fName: "nuwan",
        lName: "karunarathna",
        getName: ƒ (),
        getAge: f (),
        __proto__: Object
    }
}
Enter fullscreen mode Exit fullscreen mode

As we can see the prototype of the newPerson has the getName() method which is the original method but now newPerson also has its own method called getName() . So at runtime, when we call the getName() of the newPerson JavaScript will check whether the newPerson has a own method called getName() and in our case it has, so JavaScript executes that method and ignores the getName() of the prototype of the newPerson. This is called shadowing methods. Now in contrast when executing the getAge() JavaScript checks whether the newPerson has a own method called getAge() but it doesn't and now it will check the prototype of the newPerson to find a method with that name to execute it and luckily it does so it will be executed but if it did not had a matching method, JavaScript will perform this searching through the prototype chain until a method is matched.

So this is how we can override methods in JavaScript and we learned how it is happening underneath with the prototypes. We can use the above technique for override properties too.

So in summary we can easily override methods and properties in JavaScript and it is good to have an understanding about how it is actually happening too.

Let's meet in another article. Until then, Happy coding! :)

Discussion (0)