Class & Interface
How do we write object orientated code in ES6?
Object Orientation in JavaScript
JavaScript has a prototype-based, object-oriented programming model. It creates objects using other objects as blueprints and to implement inheritance it manipulates what’s called a prototype chain.
We normally call the way object orientation is implemented in C++ or Java as the Classical OO Pattern and the way it’s implemented in JavaScript as the Prototype Pattern.
Although the prototype pattern is a valid way to implement object orientation it can be confusing for newer JavaScript developers or developers used to the classical pattern.
So in ES6 we have an alternative syntax, one that closer matches the classical object orientated pattern as is seen in other languages.
Tip
Note
class
syntax but also adds some other feature like access modifiers and interfaces, so in this lecture we’ll be writing TypeScript rather than pure ES6.
Class
A class
is a blueprint for creating objects with specific functions and properties already attached to it, let’s go through a simple example line by line:
Copyclass Person { (1)
firstName = ""; (2)
lastName = "";
constructor(firstName, lastName) { (3)
this.firstName = firstName;
this.lastName = lastName;
}
name() { (4)
return `${this.firstName} ${this.lastName}`;
}
whoAreYou() {
return `Hi i'm ${this.name()}`; (5)
}
}
1 | We define a class using then class keyword. |
2 | We describe the properties we want on our class instance. |
3 | Each class has a special constructor function, this is called when we create an instance of a class with new |
4 | We describe the functions, also known as methods, that we want on our class instance. |
5 | this in a method points to the class instance, the object that is created using this class. |
Class Instance
A class is a blueprint for creating an object, we call that created object an instance of a class, or a class instance or just instance for short.
We instantiate a class by using the new
keyword and when that happens JavaScript calls the constructor
function. We can pass to the constructer arguments which it uses to initialise properties or call other function, like so:
Copylet asim = new Person("Asim","Hussain");
The above creates an instance of the Person class called asim.
The asim instance has the same properties and functions that are described on the Person class:
Copylet asim = new Person("Asim","Hussain");
asim.whoAreYou()
// "Hi i'm Asim Hussain"
Inheritance
A class can inherit from another class. We can create a class blue-print that extends an existing class blue-print by adding other methods or properties.
We do this by using the extends
keyword, like so:
Copyclass Student extends Person { (1)
course; (2)
constructor(firstName, lastName, course) {
super(firstName, lastName); (3)
this.course = course;
}
whoAreYou() { (4)
return `${super.whoAreYou()} and i'm studying ${this.course}`; (5)
}
}
1 | We use the extends keyword to signal that this class inherits all the properties and methods from the parent Person class. |
2 | We can describe additional properties. |
3 | We use the super function to call the constructor of the parent class |
4 | We can override member functions of the parent class with our own versions. |
5 | In member functions super refers to the parent instance. |
We can then instantiate this derived class like so:
Copylet asim = new Student("Asim", "Hussain", "Angular 2");
console.log(asim.whoAreYou());
// Hi i'm Asim Hussain and i'm studying Angular 2
Access Modifiers
Everything we have learned so far about classes is pure ES6 JavaScript.
However TypeScript adds some nice functionality on top of ES6 classes, namely function and property visibility via access modifiers.
For example we can define the properties of our Person class as private
, like so:
Copyclass Person {
private firstName = "";
private lastName = "";
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
And we create a function on our Student class called test()
which tries to access one of these properties, like so:
Copyclass Student extends Person {
.
.
.
test() {
console.log(this.firstName);
}
}
And we tried to call this function from our Student
instance, like so:
Copylet asim = new Student("Asim", "Hussain", "Angular 2");
console.log(asim.test());
Compiling the above with TypeScript prints out this error:
Copyerror TS2341: Property 'firstName' is private and only accessible within class 'Person'.
By marking the firstName
property as private
it is now only visible from one of the methods on Person
class.
We can also define class methods as private
with the same effect. If we tried to call a private
method from outside of a Person class, the TypeScript transpiler throws an error.
There are 3 access modifiers:
- public
-
This is the default and means it’s visible everywhere.
- private
-
Only member functions of the class it’s declared in can see this.
- protected
-
Only the class it’s declared in and any class that inherits from that class can see this.
Constructor Shortcut
A really common pattern in constructors is to use them to initialise properties via arguments you pass into the constructor, like in our example:
Copyclass Person {
private firstName = "";
private lastName = "";
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
As long as you are using an access modifier TypeScript lets us shorten this to:
Copyclass Person {
constructor(private firstName, private lastName) {
}
}
Interfaces
TypeScript has another feature called an interface
. An interface can be used in a number of scenarios but by far the most common is when used with classes.
When used with classes the syntax looks like this:
Copyclass Person implements Human {
}
Human
in the example above is an interface. An interface lets you describe the minimum set of public facing properties or methods that a class
has.
Another way interfaces are explained is that they describe a set of rules the class has to follow, a contract it has to adhere to.
So for us a Human
interface might look like:
Copyinterface Human {
firstName: string;
lastName: string;
}
Important
If the Person class then doesn’t implement at least a firstName
and a lastName
then TypeScript throws an error like so:
Copyerror TS2420: Class 'Person' incorrectly implements interface 'Human'. Property 'firstName' is missing in type 'Person'.
Sometimes however we might want an interface to describe an optional contract. We can append ?
to the name of the property or function to mark it as optional, like so:
Copyinterface Human {
firstName: string;
lastName: string;
name?: Function;
isLate?(time: Date): Function;
}
Summary
In ES6 we now have a new way of writing object oriented code with the class
syntax.
We can inherit methods and properties of one class into another by using the extends
keyword.
Under the hood we are still using prototype based inheritance but the syntax is easier to understand and more familiar for developers who are coming from other languages.
TypeScript adds some extra functionality
Listing
Copyinterface Human {
firstName: string;
lastName: string;
name?: Function;
isLate?(time: Date): Function;
}
class Person implements Human {
constructor(public firstName, public lastName) {
}
public name() {
return `${this.firstName} ${this.lastName}`;
}
protected whoAreYou() {
return `Hi i'm ${this.name()}`;
}
}
class Student extends Person {
constructor(public firstName, public lastName, public course) {
super(firstName, lastName);
}
whoAreYou() {
return `${super.whoAreYou()} and i'm studying ${this.course}`;
}
}
let asim = new Student("Asim", "Hussain", "typescript");
console.log(asim.whoAreYou());
Caught a mistake or want to contribute to the book? Edit this page on GitHub!

Advanced JavaScript
This unique course teaches you advanced JavaScript knowledge through a series of interview questions. Bring your JavaScript to the 2021's today.
Copy[🌲,🌳,🌴].push(🌲)If you find my courses useful, please consider planting a tree on my behalf to combat climate change. Just $4.50 will pay for 25 trees to be planted in my name. Plant a tree!