Table of Contents
- An Introduction To Classes
- Classes In Detail
- Subclasses In Detail
- Classes In Action
- Closing Thoughts
1. An Introduction To Classes In JavaScript
In the previous article in this series we looked at function constructors as one of the recommended ways to set an object's prototype in JavaScript, and we noted that although, there are other ways of doing this, concocting them into one discursive article would be a disincentive to readers.
You can get a refresher from this article here:
An Easy Guide To Understanding Constructors In JavaScript
Lawrence Eagles ・ May 9 '20 ・ 10 min read
In this article we will pick up where we left off by looking at Classes in JavaScript.
This is another recommended method of setting an object's prototype in JavaScript and it makes for a very interesting discourse in this OOP (Object Oriented Programming) in JavaScript series.
Below are some gleanings from a previous post in this series:
✨ The classical inheritance or class bases inheritance involves writing classes; which are like blueprints of objects to be created. Classes can inherit from classes and even create subclasses.
✨ In the prototypal inheritance an object inherits its properties and methods from its prototype object. And sometimes, a search down the prototype chain is necessary for an object to access some properties and methods.
You can get a refresher from this article here:
Understanding Prototypal Inheritance In JavaScript
Lawrence Eagles ・ Apr 23 '20 ・ 13 min read
🎉 So what is interesting is that JavaScript introduced classes in ECMAScript 2015 but is primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.
Although, one can say in a nutshell; classes in JavaScript are just new syntax for the same old prototypal inhertance. They however, have significant improvements over function constructors and are a very powerful addition to the JavaScript programming language.
Lets take a deeper look at classes in JavaScript in the next section.
2. Classes In Detail
✨ In JavaScript classes are functions. And since all functions are objects in JavaScript, classes are also objects.
Classes are Functions
Kindly run and consider the code below. Be sure to expand the console.log output for a more detailed result
From the results of the code above we can see the follow:
- The Person class is a function with a
name
property in this case Person. - It has a
prototype
property which points to thePerson {}
object. Take note this is not the prototype of the Person class. But this is the prototype of all the instances of the Person class.
💡 The prototype property of a class is not the prototype of the class. It is the prototype of every object created from that class
- The Person class has a
__proto__
property which points to the function prototype. This is the prototype of the Person class.
Lets elaborate on the last two points above with some code samples.
Kindly run and consider the codes below:
From the results of the code above it should be clear that Person.prototype
is different from Person __proto__
. The former is the prototype of all instance of the Person class and the latter is the prototype of the Person class itself.
🎉 If this feels a little fast-paced for you, please know that I am building upon what I have already covered in the previous two articles.
However, if you have not been following or for some reason you are finding this section a bit puzzling, kindly refer to my previeous articles in this series. I have already shared their links in section 1.
Like regular functions in JavaScript you can have a class declaration and a class expression.
Kindly examine the code below
// A class declaration
class Person_Dec {
constructor(name, gender) {
this.name = name;
this.logo = gender;
}
}
// An Unnamed class expression
const Person_Exp = {
constructor(name, gender) {
this.name = name;
this.logo = gender;
}
}
// Named class expression
const Person_Exp2 = class Person_Exp {
constructor(name, gender) {
this.name = name;
this.logo = gender;
}
}
All three methods above are valid ways to implement a class in JavaScript.
Classes are Objects
In other programming languages like C#, C++ and Java, that uses classical (class-based) inheritance the class is a template or a blueprint that details the structure of an object. Objects are built from them but they are not objects.
In JavaScript however, the Class is a special function and all functions in JavaScript are objects hence the JavaScript class is an object. JavaScript still uses prototypal inhertance. Classes however, provide a new and improved way to set the objects prototype. We will look at this in a moment.
Kindly consider the results of the code below
Above is the declaration of a Person Class with a normal method
and a
static method
.
From the results of running the code, we can see the following.
- The instance of the Person class (the developer object) inherites the properties and methods of the Person class.
Thus we were able to call the getName
method on the developer object.
console.log("Developer's Name", developer.getName()); // calls the getName function inherited from the Person Class
// returns "Lawrence Eagles"
- Using the
static keyword
with a method, creates a static method for the class.
//static
static getPersonGender () {
return "male"
}
These methods are not inherited by the instances of a class hence they cannot be called on the instances of a class itself.
You can prove this by uncommenting this line from our code sample:
//console.log("Developer's gender", developer.getPersonGender());
Notice however, that we where able to successfully call the getPersonGender
method on the Person class itself.
console.log("Person's gender", Person.getPersonGender()); // calls the getPersonGender static method of the Person class
// This call is successful because the static method is available on the Person class
💡 Static methods aren't called on instances of the class. Instead, they're called on the class itself.
They are often utility functions, such as functions to create or clone objects.
- The prototype of the instance of the Person class (the developer object) is the
Person {}
object. We have already noted that the Person object have aprototype
property which points to thePerson {}
object and serves as the prototype of all instances of the Person class. Here we get an elboration on this with codes samples.
console.log("Developer's Prototype", developer.__proto__); // gets the prototype of the developer
3. Subclasses In Detail
Besides creating instance of a class we can also extend
a class (create subclasses from an existing class). This is kind of advance and it is a very powerful feature of the JavaScript class.
JavaScript introduced a new keyword for this purpose called extends
.
💡 The extends keyword is used in class declarations or class expressions to create a class that is a child of another class.
Kindly run and consider the code below:
The code above shows a Person class and a Developer subclass created from the person class. Below are some comments to elaborate on the code above.
In other to create a subclass we extend the parent class using the keyword
extends
Hence:class Developer extends Person
.The
super keyword
is used to access and call functions on an object's parent. Notice we usedsuper.sayName()
in thegetBio
method of the Developer subclass to call the sayName method of the Person Parent class.Calling
super()
method inside a contractor would call the constructor of the parent class.
In our example calling thesuper method
inside the Developer's subclass constructor would call the Person class constructor. Now any arguments passed to thesuper()
would also be passed to the parent class constructor. I will elaborate with a small contrived perspicuous example
Kindly run and consider the code below
Above we created a Square
subclass from the ObjectFactory
class. Notice that the ObjectFactory
constructor expects two parameters viz height
and width
. Values for these are provided when we call super()
in the Square
subclass.
constructor(length) {
super(length, length);
}
when the Square1
and Square2
instances where created the argument provided to the length parameter was passed down to super()
which calls the parent (ObjectFactory) constructor with these arguments.
const Square1 = new Square()
const Square2 = new Square(4)
The height
and width
property of the Square1
instance is undefined
however, because no argument was provided when it was created by invoking the Square
subclass.
const Square1 = new Square() // no argument provided.
- The
super()
method must be called in the constructor in a class before thethis keyword
is made available else we get a reference error. Again I would elaborate with an example.
Note running the code below would throw an error this is delebrate:
To get the code to work properly kindly move the super(length, length)
above this.name = "Square Object"
.
- Unlike instances of a class, static methods can be called on a subclass. Let's elaborate with some code examples.
Kindly run and consider the code below:
In our code example above we noticed that the
Person Class has a static method
viz:
static logGreeting() {
console.log("Good day " + this.name);
}
This method was successfully called by the developer subclass.
// calls the logGreeting static method of the Person Class in the developer subclass
console.log("greeting from developer", Developer.logGreeting())
Static methods
however cannot be called on instances of a class. You can test this by on commenting this line and rerun the code:
//console.log("greeting from developer", ReactGuy.logGreeting())
When a subclass is created from a class, the class becomes its prototype.
We prove this from our code sample above with this line:
console.log("Developer Prototype", Object.getPrototypeOf(Developer))
💡 The
Object.getPrototypeOf()
method returns the prototype of any object passed to it as an argument.
From the result of our code above we can see that the prototype of the developer subclass is the Person parent class.
Classes In Action
I belive by now we should be pretty comfortable with the JavaScript class.
Classes in JavaScript are more than just a new way to create objects and set their prototype. As we have seen above they come with a number of interesting features.
In addition, they would throw an error when they are called without the
new operator
this helps developer to avoid nasty bugs common when using function constructors
Classes power several popular JavaScript frameworks and libraries like React.js and Angular. Their rich feature set paves the way for several advanced design patterns in different JavaScript libraries and frameworks.
Let's see some real life code examples.
Kindly examine the code below
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
Above is the boilerplate code for an ErrorBoundary component
in React.
Although, this is not an article on React; I only want us to see classes in action in some of the most advanced JavaScript library.
💡 React 16 introduces a new concept of an “error boundary”, in other to catch error anywhere in your application and render a fallback UI instead of allowing the whole applicaiton to crash because of a JavaScript error.
It is an advance design pattern in React.js
- Notice the
ErrorBoundary component
is implemented with a JavaScript class by extending the React Component class.
class ErrorBoundary extends React.Component
- Notice how
super(props)
was called beforethis keyword
was used in the constructor.
constructor(props) {
super(props);
this.state = { hasError: false };
}
- Notice the
static method getDerivedStateFromError
of the ErrorBoundary subclass. It is used to render a fallback UI after an error has been thrown
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
If you are not a React.js Developer you may not fully comprehend what is going on here, but that is understandable. My aim here is to show you some of the real world implementation of classes in regards to our discourse.
5. Closing Toughts:
It has really been a long article and if you got here you are really appreciated and I am more than elated.
I really hope that at this point, you can see the benefits of our long discussion and at least got a thing or two from this article. If so, I would be honoured if you would share it with you friends and colleagues, while also looking forward to hearing your opinions, comments, questions, or requests (in case anything is not clear) at the comments section below.
Top comments (4)
Thanks Lawrence for this useful guide.
This is the best post regarding "Class".
Your thinking process is very clear.
Thanks.
One of the best articles I have ever read on Prototypes. 🔥
I was struggling with class in javascript. Thanks a lot for this easy to understand post