ES6 Object Oriented
This is the part of a series of blogs on the new features on the upcoming ECMAScript 6 (ES6) specification which JavaScript implements.
In this blog we focus on the class-based object oriented programming introduced in ES6.
Prototype-based #
Traditionally JavaScript is a prototype-based programming language which “classes are not present, and behavior reuse (known as inheritance in class-based languages) is accomplished through a process of decorating existing objects which serve as prototypes” - Mozilla MDN.
This basically means that we are able to mimic object oriented programming by creating an object with prototype methods which other objects will then use as a base or inherit.
var Animal = function(sound) {
this.sound = sound;
};
Animal.prototype.speak = function() {
console.log(this.sound);
};
var cat = new Animal("Meow");
var aznCat = new Animal("Miao");
cat.speak(); // Meow
aznCat.speak(); // Miao
// Cat constructor
function Cat(sound, name) {
Animal.call(this, sound);
this.name = name;
}
// Inheritance call
Cat.prototype = Object.create(Animal.prototype);
// Method overwriting
Cat.prototype.constructor = Cat;
Cat.prototype.speak = function() {
console.log(this.name + " says " + this.sound);
}
var superCat = new Cat("meowmeowmeow", "Cinder");
superCat.speak() // Cinder says meowmeowmeow
console.log(superCat instanceof Animal) // True
console.log(superCat instanceof Cat) // True
Here we can see how Cat inherits prototype methods from Animal function (using the instanceof
check) yet still retains its own implementation for the constructor
and the speak
method. We use Object.create
rather than new Animal()
since calling new
would run the constructor function.
Class-based #
JavaScript is traditionally prototype-based since web browsers and client side computers were not powerful enough back in the day. It was seen as beneficial to JS since objects are essentially functions and we can create new objects at run time without defining classes (static code). However ES6 brings class-based object oriented programming into the world of JavaScript to have more modular, clean, and understandable code.
ES6 provides JS with structure when creating class-like functions by actually creating classes instead. This allows developers to have interoperable code with clear design patterns and readable declarations. ES6 Classes support prototype-based inheritance, super calls, instance and static methods, and constructors.
class Animal {
constructor(sound) {
this.sound = sound;
}
speak() {
console.log(this.sound);
}
}
class Cat extends Animal {
constructor(sound, name) {
super(sound); // calls the parent constructor
this.name = name;
}
speak() {
// super.speak() to use Animal/Parent's speak method
console.log(this.name + " says " + this.sound);
}
}
let superCat = new Cat("meowmeowmeow", "Cinder");
superCat.speak() // Cinder says meowmeowmeow
console.log(superCat instanceof Animal) // True
console.log(superCat instanceof Cat) // True
Here we can see how the code is more structured and modular than before. However prototypical inheritance will not be demised in ES6 so you’re still free to develop in this fashion as for now.
Encapsulation #
Encapsulation is when the data of an object is not directly exposed. This is usually done by returning a function that contains a limited set of public functions that interacts with the private data in the original function.
var Bunny = function(cuteFactor) {
var cuteFactor = cuteFactor;
function getCF() {
return cuteFactor*1000;
}
return {
setCuteFactor: function(value) {
cuteFactor = value;
}
}
}
Abstraction #
Abstraction in JavaScript is using interfaces by extending from them. Here are a couple of cases the ES6 Classes provides us with code readability and maintainability by defining the prototype inheritance of each Class.
- Class without extending anything
- Prototype of the Class will be
Function.prototype
- Prototype of
Class.prototype
isObject.prototype
- Prototype of the Class will be
- Class extending null
- Prototype of the Class will be
Function.prototype
- Prototype of
Class.prototype
isnull
- Prototype of the Class will be
- Class extending AnotherClass
- Prototype of the Class will be
AnotherClass
- Prototype of
Class.prototype
isAnotherClass.prototype
- Prototype of the Class will be
- Class extending AnObject
- Prototype of the Class will be
Function.prototype
- Prototype of
Class.prototype
isAnObject
- Prototype of the Class will be
Polymorphism #
Since JavaScript is not strongly typed, there are no hard requirements when variables are passed in as arguments to a function (unless you are using static type checkers such as Flow or TypeScript). Basically if you want to make sure that the variable passed has certain properties then you would need to leverage the instanceof
function to assure you are working with the right object.
Cat.prototype.eat = function(food) {
if (food instanceof catFood) {
return true;
} else {
return false;
}
}
Things to note #
- Class body can only have methods, no properties
- Still no private functions in ES6 Classes
- The argument the Class is extending from (or what comes after the
extends
keyword) can be in form of an expression - Class initialization is not hoisted so it will need to be declared before used (else getting a RunTime Error) unlike function declarations which would be undefined.
- If there is no constructor defined then it will default to the following:
constructor(...args) { super(...args); }