JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.
In this article, we’ll look at the best practices for dealing with classes and constructors.
Always Use the Class Syntax. Avoid Manipulating Prototype
Directly
The class syntax in JavaScript is just syntactic sugar on top of the constructor function syntax.
To create a constructor function with an instance method, we have to write something like the following code:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `hi ${this.name}`;
};
In the code above, we have the Person
constructor function, which has the name
parameter. We set the name
parameter to this.name
.
Then we defined the greet
instance method, we have the returns the string that has the word ‘hi’ with this.name
.
this.name
would be the name
member that’s in the Person
instance.
If we log the value of the following expression:
new Person('jane').greet()
Then that returns the string 'hi jane’
.
The old constructor function makes creating constructors harder. We’ve to add instances to its prototype
property, which means that we can’t put all the members in one place.
Instead, we should use the class syntax, which lets us keep all the members inside one class.
For instance, with the class syntax, we can rewrite the code as follows:
class Person {
constructor(name) {
this.name = name;
}
greet() {
return `hi ${this.name}`;
};
}
In the code above, we have the Person
class, which encapsulates all the members of the constructor, including instance variables and methods, all in one entity.
That’s much better than adding properties to a prototype. Also, we make sure that we have our initialization code in the constructor
method instead of within the function itself.
This is much clearer as we know for sure that the value of this
is the Person
instance. It’s not so clear what the value of this
is in the constructor function example by reading the code.
Use extends
for Inheritance
The extends
keyword that we can add to a class makes doing inheritance with constructor function easily.
With it, we can create a child class that inherits from the parent class without creating constructor functions that have to call and modify prototype
.
We’ll also get an error if we forgot to call the parent constructor by calling super
in the constructor
if we have the extends
keyword.
For instance, instead of writing the following code with constructor functions as follows:
function Animal(name) {
this.name = name;
}
Animal.prototype.greet = function() {
return `hi ${this.name}`;
}
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Animal;
In the code above, we have to do many things to create a Dog
constructor as the child of the Animal
constructor.
We’ve to call the Animal
constructor by writing Animal.call(this, name);
. Then we have to create Dog
‘s prototype
by calling Object.create
with Animal
‘s prototype
as we did with:
Dog.prototype = Object.create(Animal.prototype);
Also, we have to set the parent constructor for Dog
to Animal
by writing:
Dog.prototype.constructor = Animal;
As we can see, we need many lines to create a Dog
constructor that inherits from Animal
.
We can only make sure that we did that all that correctly by calling the greet
method from the Dog
instance as follows:
new Dog('jane').greet()
Since we did inheritance with constructors correctly, we can call the Animal
constructor with ease.
We instead write the following with the class syntax:
class Animal {
constructor(name) {
this.name = name;
}
greet() {
return `hi ${this.name}`;
};
}
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
}
All we have to do in the code above is calling the parent constructor from Dog
‘s constructor with super
and add the extends
keyword. If we forgot to call super
, we’ll get an error.
Also, the class member code is all within the curly brace so we can tell what
Therefore, using the class syntax with extends
is much clearer. There’s also less chance for mistakes.
Conclusion
The class syntax should always be used instead of the constructor syntax. It’s better for defining standalone constructors and also for inheriting from other constructors.
The class syntax is equivalent to constructor functions.