Introduction
Every object in JavaScript, a prototype-based language, contains an internal property named the [[Prototype]]
. Its utility extends to the manipulation of object properties and methods. Mimicking the object-oriented design pattern of JavaScript, most developers utilize construction functions. One of these functions is the concept of classes, introduced to JavaScript via the ECMAScript 2015 language specification.
JavaScript’s classes provide a sharper, more elegant syntax, sometimes described as “syntactical sugar,” while not offering much along the way of supplemental functionality. The classes make the syntax more relatable for developers as other object-oriented languages generally also operate on this programming principle.
Functional Classes
A class in JavaScript is a function type that is declared with a class keyword. The following example will illustrate the function used for the function’s initialization, as well as the syntax expression you can use for declaring a class:
1 2 3 4 5 |
// Initializing a function with a function expression const x = function() {} // Initializing a class with a class expression const y = class {} |
For now, the function we created was empty. Next, let’s use the Object.getPrototypeOf()
method to access its [[Prototype]]
function:
1 |
Object.getPrototypeOf(x); |
Output:
You can use a similar method in the recently created class:
1 |
Object.getPrototypeOf(y); |
Output:
Both code declarations (for class
and function
) will return a function [[Prototype]]
. By using the new
keyword, any function can become a constructor instance with prototypes:
1 2 3 4 5 6 |
const x = function() {} // Initialise a constructor from a function const contructorFromFunction = new x(); console.log(contructorFromFunction); |
Output:
Similarly, you can apply this to classes:
1 2 3 4 5 6 7 8 9 10 |
const y = class {} // Initialise a constructor from a class const contructorFromClass = new y(); console.log(contructorFromClass); Output: y {} constructor: class |
Output:
While both constructor examples we illustrate are empty, the underlying syntax is evidently serving to return the same result.
Class Definition
As you might recall, we created a text-based role-playing game in our prototype and inheritance tutorial. Let’s pick up that example and update the syntax to classes from functions.
Constructor functions are set with certain parameters. Each of them is assigned this
property, about the function. By convention, the first letter of the identifier will be capitalized:
1 2 3 4 5 6 |
// Initialising a constructor function function Hero(name, level) { this.name = name; this.level = level; } |
We can observe a similar structure when this is translated to a class
syntax:
1 2 3 4 5 6 7 8 |
// Initializing a class definition class Hero { constructor(name,level){ this.name = name; this.level = level; } } |
Our familiarity with the syntax lets us know that the constructor function serves as the object blueprint. We can tell that by the capitalization of the first letter. The objective of our function is more clearly communicated by the class
keyword. The main two differences are that instead of a function
, we are initializing the class
keyword, as well as the assignments being made to the constructor()
method.
Methods of Definition
Commonly, constructor function methods are linked directly to the prototype, instead of being initialized. We can see this in the greet()
method:
1 2 3 4 5 6 7 8 9 |
function Hero(name, level){ this.name = name; this.level = level; } // Adding a method to the constructor Hero.prototype.greet = function() { return `${this.name} says hello.`; } |
The method can be associated directly with the class, simplifying the syntax by utilizing classes. Still more concise, defining a method can be done shorthand, as defined in the ES6:
1 2 3 4 5 6 7 8 9 10 11 |
class Hero { constructor(name, level){ this.name = name; this.level = level; } // Adding a method to the constructor greet() { return `${this.name} says hello.`; } } |
Let’s give these properties a visual test run by creating a new instance of Hero
with the new
keyword, then assign it some values:
1 |
const hero1 = new Hero('Varg', 1); |
To view more detail about our newly created object we can print it out with console.log(hero1)
:
The output of that action shows us a full audit of what manipulations have been applied to the hero1
object such as the application for the constructor()
and greet()
functions to the _proto_
of the object (but not as a direct method of it). This becomes clear when generating constructor functions. Things are a bit more obscure when it comes to generating classes. While classes offer a simpler and more succinct syntax, it comes at the cost of some degree of clarity.
Class Extensions
One major advantage of constructor function and class applications is their ability to be extended into new object blueprints based on the attributable nature of their parent. By doing so, we avoid code redundancy. However, we still generate objects similar enough to others, yet more specific and refined in their features.
The creation of new construction methods can be accomplished by utilizing the call()
method as can be visualized in the following example. Here, we will be creating Mage
, a more specific character class. Then, we will assign Hero
properties to it with call()
, in addition to supplementing a property:
1 2 3 4 5 6 7 |
// Creating a new constructor from the parent function Mage(name, level, spell) { // Chain constructor with call Hero.call(this,name,level); this.spell = spell; } |
From this point forward new instances of Mage
can be created using Hero’s
properties and its own specific one that can be added:
1 |
const hero2 = new Mage('John Doe', 34, 'Serial Killer'); |
Sending hero2
shows that based on the constructor, we have created a new Mage
:
To access parent functions with ES6 classes, we use the super
keyword instead of call
, and when referring to the parent class, we will use extends
:
1 2 3 4 5 6 7 8 9 10 11 |
// Creating a new class from the parent class Mage extends Hero { constructor(name, level, spell){ // Chain constructor with super super(name, level); } this.spell = spell; } } |
We can now create a new instance of Mage
the same way, then we can print hero2
to the workstation and be able to observe the output:
1 |
const hero2 = new Mage('John Doe', 34, 'Serial Killer'); |
The output will be almost identical in this case, except for [[Prototype]]
in the class construction will link back to the parent, Hero
. Let’s compare the entire process of initialization, supplementing methods, as well as the inheritance of the constructor function and class in the following two code snippets:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function Hero(name, level) { this.name = name; this.level = level; } // Adding a method to the constructor Hero.prototype.greet = function() { return `${this.name} says hello.`; } // Creating a new constructor from the parent function Mage(name, level, spell) { // Chain constructor with call Hero.call(this,name,level); this.spell = spell; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// Initialising a class class Hero{ constructor(name, level){ this.name = name; this.level = level; } // Adding a method to the constructor greet() { return `${this.name} says hello.`; } } // Creating a new class from the parent class Mage extends Hero { constructor(name,level,spell){ //chain constructor with super super(name,level); //Add a new property this.spell = spell; } } |
While the syntax is significantly different, the final result is virtually identical. With classes, we get a more concise way of creating blueprints for objects. Constructor functions will let us have a refined picture of what’s happening under the hood.
Final Thoughts
This tutorial focuses on the key differences and similarities between JavaScript constructor functions and ES6 classes. Both will serve to exhibit the behavior of inheriting the properties of the parent object, behavior inherent to JavaScript.
In order to be an effective JavaScript developer, one must understand these prototypical inheritance attributes. Most JavaScript libraries, such as React often reference the class
syntax, so it helps to be familiar with classes when working with the platform.
Here are some more resources from our blog that will help you further utilize JavaScript:
- Take a look at our guide on adding JavaScript to HTML.
- If you are building your own web application, take a look at our guide on how to choose the best server setup.
- If you want to learn how to set up a blog with Ghost, take a look at this tutorial.
Happy Computing!
- Removing Spaces in Python - March 24, 2023
- Is Kubernetes Right for Me? Choosing the Best Deployment Platform for your Business - March 10, 2023
- Cloud Provider of tomorrow - March 6, 2023
- SOLID: The First 5 Principles of Object-Oriented Design? - March 3, 2023
- Setting Up CSS and HTML for Your Website: A Tutorial - October 28, 2022