Keep your privates private in JavaScript — Part 1

Image Credit: https://sputniknews.com/science/201801231060990513-scientists-discover-chemical-life-building-blocks/

The four core principles of OOP are:

  1. Encapsulation
  2. Abstraction
  3. Inheritance
  4. Polymorphism

This article is not meant to teach the fundamentals of OOP, if you are new to OOP, or you do not understand the main principles of OOP, listed above, I recommend Alexander Petkov’s article: https://medium.freecodecamp.org/object-oriented-programming-concepts-21bb035f7260

This article aims to demonstrate how to implement one of the Core principles of OOP in JavaScript — Encapsulation. Encapsulation simply means, keeping an object’s state private to the object.

Take a look at this code, written in Java.

public class User {
private String name;
private String password;

User() {
}
}

The above code is how you would create a User class in Java. The private access modifier keyword simply makes name private to an instance of the class. One of the surprises you will get when moving from Java or any like language to JavaScript is that there are no private access modifiers for access control, How do you truly implement information hiding (encapsulation) in JavaScript?

JavaScript supports functional programming patterns, imperative, as well as prototype-based object-oriented programming patterns.

Making your object state private is called Encapsulation in OOP. In Java, merely adding a ‘private’ keyword, in front of your state variable, as we saw in the above code automatically makes it private. JavaScript has no such provision for making private variables private.

function User(name, password) {
this.name = name;
this.password = password;
this.isSuperUser = false;
this.sessionStarted = false;
}
User.prototype = {
getUserName: function() {
return this.name;
},
setUserName: function(name) {
this.name = name;
}
}

The above code is a User constructor (a function that we can use to create user objects).

Classes were introduced in ES6. Using ES6 Class Syntax we have:

class User {
constructor(name, password) {
this.name = name;
this.password = password;
this.isSuperUser = false;
this.sessionStarted = false;
} getUserName() {
return this.name;
}
[.... methods]
}

Instantiating (creating a new object) of User is the same for both cases:

const user = new User('arya', 'winterfell')

Our class has a method getUserName, that’s truly useless in this case, because we do not need it to change the user’s name, we can just do:

user.name = 'robb' 

and that would change our user’s name to robb. Our object's state truly is not private (encapsulated). The big question is: How do we make our object’s state private?

This article only treats one method, and that’s using Closures

Closure is one of the concepts of JavaScript that truly makes it a powerful language. Here’s a classic function that demonstrates closures:

function multiplier(num) {
return function multiplierInner(value) {
return num * value
}
}
const threes = multiplier(3)
const six = threes(2) // 6
const nine = threes(3) // 9

If you are not familiar with Closures, This MDN guide explains it well: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

Closures work on the underlying concept of Scopes: In JavaScript, a function creates a scope, We can say multiplier creates a scope, and multiplierInner also creates another scope.

Let’s make our state private using Closures, we will use a normal constructor function to demonstrate the first example

function User(name, password) {  // private variables
const name = name
const password = password

// public methods
this.getUserName = function() {
return name
}
this.setUserName = function(newName) {
name = newName
}
}

Instantiating User:

const user = new User('arya', 'winterfell')
console.log(user.name) // undefined

Our object state is truly private, we have achieved encapsulation! Yes, but at the cost of something else:- let’s call that something else heap_problem. Everytime we create a user object, we will be creating a new getUserName and a new setUserName function objects. That is not efficient, but we have made our object truly private.

To get around the unnecessary function creations at every object instantiation we can do this:

function makeUser(name, password) {
const name = name
const password = password

return {
// public methods
getUserName: function() {
return name
},
setUserName: function(newName) {
name = newName
}
}
// The only difference with this implementation is that
// we won't be using the new operator to get our object
const user = makeUser('arya', 'winterfell')
user.getUserName() // arya
user.setUserName('robb')
user.getUserName() // robb

You may ask, this pattern does not support Inheritance, if you mean Classical inheritance, no it doesn’t. But it very well supports JavaScript inheritance pattern (Prototype-based) and, I find it more expressive than classical pattern.

const userClone = Object.create(user)// userClone.__proto__ now points to user
// awesome, right?

Finally, let’s see how to implement the above code in JavaScript ES6 Classes, using Closures to make our state private:

class User {
constructor(name, password) {
let username = name
let userPassword = password
// [ private methods ] // public methods this.getUserName = function() {
return username
}
this.setUserName = function(newUserName) {
username = newUserName
}
}
const user = new User('arya', 'winterfell')
user.name = 'bran'
user.getUserName() // arya

The only thing I do not like in this implementation is creating a method in the constructor function. In the next article that follows this one, we will look at other ways we can encapsulate our states.

Problem Solver, Software Engineer @Andela, JavaScript Freak, Freelance Technical Writer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store