How To: "Private" In JavaScript (ES6) Classes

Introduction

 
While using JavaScript, you might be dearly missing our friend "private" from statically-typed languages like C#, C++, and Java. Using a little finesse, we can actually achieve true encapsulation using local variables in vanilla JavaScript (ES6) classes.
 
There are many instances where we want to hide an object's properties from public view. In other words, we only want to allow the object's methods to operate on these properties. But how can we do this in a dynamically-typed language like JavaScript?
 
To do this, we can utilize block scoping using const or let within the class constructor, and provide public methods that can return or operate on these encapsulated variables.
 
Example - The Counter Component
 
For this example, let's say we're making a Counter component. This will be a reusable component that encapsulates a count and allows the user to increase or decrease the counter linearly. The user should be able to look at the count variable, but they shouldn't be able to reach in and change it by hand.
 

Without Encapsulation

 
Our first attempt could look something like this,
  1. class Counter {  
  2.     constructor(startAt = 0){  
  3.         this._count = startAt;  
  4.     }  
  5.     increase(){  
  6.         ++this._count;  
  7.     }  
  8.     decrease(){  
  9.         --this._count;  
  10.     }  
  11.     get count(){  
  12.         return this._count;  
  13.     }  
  14. }  
This will work, but this._count isn't really encapsulated properly. The consumer of this class could easily reach in and change the value.
 
In order to fix this, we'll have to change this class around a bit.
 

Encapsulating the Component 

 
First, instead of making _count an object-level property, we'll restrict it to the scope of the constructor, and add an appropriate getter for it. We'll still use the ES6 get syntax for ease-of-use
  1. class Counter {  
  2.     constructor(startAt = 0){  
  3.        let _count = startAt;  
  4.   
  5.        this.getCount = () => _count;  
  6.     }  
  7.     get count(){  
  8.         return this.getCount();  
  9.     }  
  10. }  
This might seem strange at first. If so, take a moment to play around with this and see what it does. the _count variable can not be touched outside the class constructor, effectively making it private. 
 
This is cool, sure. But how do we operate on the value of _count?
 
We can do the same thing as this.getCount() because everything in the constructor has block-level access to _count, and hence will keep it alive while the object is being used.
  1. class Counter {  
  2.     constructor(startAt = 0){  
  3.        let _count = startAt;  
  4.   
  5.        this.getCount = () => _count;  
  6.   
  7.        this.increase = () => ++_count;  
  8.        this.decrease = () => --_count;  
  9.     }  
  10.     get count(){  
  11.         return this.getCount();  
  12.     }  
  13. }  
Great! Our variable _count is now truly encapsulated. You won't be able to see or access _count from outside the class itself, which is perfect for our needs.
 
The class can be used exactly like the first version of our component, without making any changes to the consuming code.
  1. const counter = new Counter();  
  2. counter.increase();  
  3. console.log(counter.count);  

Conclusion

 
This strategy for achieving encapsulation in JavaScript objects may add slightly more boilerplate to the class definition itself, but what it gives you in return may be worth it.  
 
Hopefully this information proves useful to you!
 
Stay safe everyone.


Similar Articles