What is the difference between creating an instance of object with new keyword and extending a class in JS?
First example with new keyword;
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
const dog = new Animal("Golden")
dog.bark = function(){console.log("bark")}
dog.bark()
Second example with extending:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof!');
}
}
const myDog = new Dog('Fido');
console.log(myDog.name); // expected output: "Fido"
myDog.bark(); // expected output: "Woof!"
Are these two doing the same thing? Which one should I use?
4
Answers
Use depends on your needs; if you want to add unique behavior to a single instance, you can use the first approach. If you want to create a new class with additional functionality, you can extend an existing class using the second approach.
When extending a class, you can very easily construct many new instances using your new behavior. When directly adding values to a constructed instance, that behavior is not shared and only exists for that one instance. The most common approach would be to extend the class, unless your subclass is only going to be used in one place, where this practice is still uncommon to see.
There’s a reason for using inheritance and it’s often to do with avoiding injection of individual functions like you do with
dog.bark
. There are cases where individual customization is the best option, but for an entire "class" of objects with similar properties, this is not usually the best call.A class communicates a lot more about what it is, and importantly, how it can and should be used. If you have a
Dog
here then you know how it works, there’s no ambiguity. If you use the injection model, you will need to probe for individual methods and even then there’s no certainty as to if they’ll work as expected.This is especially relevant with strong typing as you might get with TypeScript.
In OOP, classes describe objects (instances) by their common behaviour and properties. Extending a class means defining a subclass: Providing a more specific type of class than the superclass.
JavaScript allows you to dynamically set new properties on objects. Using this to effectively implement a subclass without actually defining a subclass results in ambiguity:
(Without duck-typing) you will be unable to differentiate between objects of that abnormal "subclass" and those not of that "subclass" (but its "superclass").
In other words: Implementing on the objects individually results in the properties to not be shared, since they don’t exist on a class (read: prototype).
Consider using a proper subclass if you require more than one such object or have to differentiate between them by (proto)types. Personally, I’d recommend using subclasses when the object already has a class.