JavaScript OOP : Encapsulation
This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
- Pillars of Objected-Oriented Programming
- JavaScript Objects, prototype, constructor, & Object constructor
- Object Creation in JavaScript
- JavaScript OOP : Abstraction
- JavaScript OOP : Encapsulation
- JavaScript OOP : Inheritance
- JavaScript OOP : Polymorphism
- JavaScript OOP : Inheritance vs Composition
Let's demystify encapsulation in this episode. As a reminder, encapsulation is all about information hiding. In a simple sentence, this means we as developers should try by all means to ensure our internal implementation details never leak to the outside or specific property never get accessed from the outside and also not modifiable from the outside if our intention is not to do so.
By design, JavaScript doesn't have the concept of private access modifiers like in strongly typed languages like C# and Java, but they are ways to ensure a property not intended to be accessed from the outside remains so. We will be looking at ways to ensure encapsulation for our object. We will continue to examine the CassettePlayer object from the last episode:
function CassettePlayer(cassette){
this.cassette = cassette;
this.play = function(){
console.log(`I am playing ${this.cassette}`);
};
this.pause = function(){
//pause cassette
}
this.stop = function(){
//stop playing
};
this.record = function(){
//record onto a cassette
};
this.forward = function(){
//forward cassette
};
this.rewind = function(){
//rewind cassette
};
this.eject = function(){
//eject cassette
};
}
let cassetPlayer = new CassettePlayer("Hip-hop");
cassetPlayer.play() // I am playing Hip-hop
Visualising the CassettePlayer's property:
If you've been following you must have noticed I mentioned there was an issue in the previous post and how we are going to use encapsulation to solve the problem.
the this.cassette property of the CassettePlayer object is not meant to be accessed or modified from outside. This is dangerous as anyone can cause the state of our object to change intentionally or by accident. It is possible to do something like cassetPlayer.cassette = "something else" This should never happen as the CassettePlayer object depends or make use of this property internally.
Let's see how to resolve the problem encapsulating away internal property: To make them private and not accessible from the outside.
let & const keywords
The let and const are introduced to JavaScript in the ECMAScript 6 or ES6 features. They are block-scoped modifiers, meaning if you declare a variable with the let or const keyword, that variable will only be accessible within the block it was declared.One fundamental difference between let and const is that once you declare a variable using const, value of that variable cannot be changed. Apply that to our CassettePlayer object we have:
function CassettePlayer(cassette){
const _cassette = cassette;
this.play = function(){
console.log(`I am playing ${this.cassette}`);
};
this.pause = function(){
//pause cassette
}
this.stop = function(){
//stop playing
};
this.record = function(){
//record onto a cassette
};
this.forward = function(){
//forward cassette
};
this.rewind = function(){
//rewind cassette
};
this.eject = function(){
//eject cassette
};
}
let cassettePlayer = new CassettePlayer("Hip hop");
cassettePlayer.play();
console.log(cassettePlayer);
Our internal variable is now concealed and not accessible from the outside. The CassettePlayer object now satisfies abstraction and encapsulation.
Revealing Module Pattern
The Revealing module pattern is a JavaScript design pattern that supports and enforces encapsulation. This pattern helps you decide what you want to expose and not expose. Let have a look:
function cassettePlayer(cassette){
var _cassette = cassette;
function play(){ console.log(`I am playing ${_cassette}`); }
function pause(){}
function stop(){}
function record(){}
function forward(){}
function rewind(){}
function eject(){}
function connectToWifi(){} // Not accessible!
return {
play: play,
pause: pause,
stop: stop,
record: record,
forward: forward,
rewind: rewind,
eject: eject
};
}
The connect connectToWifi property is not accessible from the outside even if you try to access it.
By all means, this is not the exhaustive list of how to create private properties in JavaScript. In other not to get too ahead of ourselves, we'll stick to these for now. If you want to explore further, have a look at ES6 symbols and weakMaps. Symbols and weakMaps can also be used to create private properties. We will be exploring them further in the future post on ES6.
I hope you have learned something new today.
Happy coding.