Classes in JavaScript
Introduction
Every object (like the ones we have discussed here) in JavaScript has a hidden internal property called prototype that can be used to extend the object's properties and methods.
Classes in JavaScript are often described as providing flavor over prototypes and inheritance because they present a cleaner and more elegant syntax. Because other programming languages use classes, the class syntax in JavaScript makes it more straightforward for developers to move between languages.
JavaScript class can be seen as a type of function (object), and they are declared with the class keyword.
Example:
// Initializing a function with a function expression
const games = function() { }
// Initializing a class with a class expression
const games = class { }
Defining a Class:
We start by creating a constructor function (object). A constructor function is initialized with a number of parameters, which would be assigned as properties of this, where this refers to the function itself.
By convention, the first letter of the identifier would be capitalized
Example:
newClass.js
// We initialize a constructor function (object) called Employee
function Employee(Fname, Lname) {
this.Fname = Fname;
this.Lname= Lname;
}
Translating this to the class syntax, as shown below, we see that it is structured very similarly.
newClass.js
// We initialize a class definition
class Employee {
constructor(Fname, Lname) {
this.Fname = Fname;
this.Lname= Lname;
}
}
A constructor function (object) is meant to be an object blueprint by the capitalization of the first letter of the initializer (which is optional) and through familiarity with the syntax. The class keyword communicates in a more straightforward fashion the objective of our function. The only difference in the syntax of the initialization is using the class keyword instead of function, and assigning the properties inside a constructor() method.
Methods:
The common practice with constructor functions is to assign methods directly to the prototype instead of in the initialization, see example below.
newClass.js
function Employee (Fname, Lname) {
this.Fname = Fname;
this.Lname= Lname;
}
// We add a method to the constructor
Employee.prototype.details= function() {
return this.Fname +"" + this.Lname;
}
With classes this syntax is simplified, and the method can be added directly to the class.
newClass.js
class Employee {
constructor(Fname, Lname) {
this.Fname = Fname;
this.Lname= Lname;
}
//Adding a method to the constructor greet()
details(){
return this.Fname +"" + this.Lname;
}
}
Now lets see how to access these properties and methods of the class or object in action.
We will create a new instance of Employee using the new keyword, and assign some values.
var emp1= new Employee("John", Thomas);
console.log(emp1)
Output
Employee{Fname : "John", Lname: Thomas}
Classes allow for a more simple and succinct syntax, but sacrifice some clarity in the process.
Extending a Class:
The advantages of constructor functions and classes is that they can be extended into new object blueprints based off of the parent. This prevents repetition of code for objects that are similar but need some additional or more specific features.
New constructor functions (objects) can be created from the parent using the call() method.
Example
We shall create a constructor function called Seniorstaff, and assign the properties of Employee to it using call(), as well as adding an additional property.
newClass.js
// Creating a new constructor from the parent
function Seniorstaff(Fname, Lname, Bonus) {
// Chain constructor with call
Employee .call(this, Fname, Lname);
this.Bonus=Bonus;
}
At this point, we can create a new instance of Seniorstaff using the same properties as Employee as well as a new one we added.
const emp2 = new Seniorstaff('Cynthia', 'Akpova', 100);
console.log(emp2)
With classes, the super keyword is used in place of call to access the parent functions. We will use extends to refer to the parent class.
newClass.js
// Creating a new class from the parent
class Seniorstaff extends Employee {
constructor(Fname, Lname, Bonus) {
// Chain constructor with super
super(Fname, Lname);
// Add a new property
this.Bonus = Bonus;
}
}
Now we can create a new Seniorstaff instance in the same manner.
const emp2 = new Seniorstaff ('Cynthia', 'Akpova', 100);
console.log(emp2)
Below is a side-by-side comparison of the entire process of initialization, adding methods, and inheritance of a constructor function and a class.
newClass.js
function Employee(Fname, Lname) {
this.Fname = Fname;
this.Lname= Lname;
}
// Adding a method to the constructor
Employee.prototype.details= function() {
return this.Fname +"" + this.Lname;
}
// Creating a new constructor from the parent
function Seniorstaff(Fname, Lname, Bonus) {
// Chain constructor with call
Employee .call(this, Fname, Lname);
this.Bonus=Bonus;
}
newClass.js
// Initializing a class
class Employee {
constructor(Fname, Lname) {
this.Fname = Fname;
this.Lname= Lname;
}
//Adding a method to the constructor greet()
details(){
return this.Fname +"" + this.Lname;
}
}
// Creating a new class from the parent
class Seniorstaff extends Employee {
constructor(Fname, Lname, Bonus) {
// Chain constructor with super
super(Fname, Lname);
// Add a new property
this.Bonus = Bonus;
}
}
Although the syntax is quite different, the underlying result is nearly the same between both methods. Classes give us a more concise way of creating object blueprints, and constructor functions describe more accurately what is happening under the hood.