In conventional object oriented programming languages like C++ and Java, we have a reserved keyword private
which is used to create private members of a class. But the scenerio is very different in the case of Javascript, where there is no keyword like private
.
Consider the following example
const Book = function(isbn){
this.ISBN=isbn
this.getISBN=function(){
console.log(`ISBN number is ${this.ISBN}`)
}
}
const book1 = new Book(123)
book1.ISBN = 987
book1.getISBN() // ISBN number is 987
In the above example, we can see that ISBN number can be easily manipulate from outside of the Book
constructor function.
Thus there is no encapsulation and data hiding, which is very important for loose coupling, code maintainability and better management of code.
Now, how can we create private members such that they can be accessible inside the constructor function only?
The answer is : Closures
Javascript provides the concept of closures, which means functions can access the environment in which they were defined, not the environment in which they are called.
Look at the code example below:
const Book = function(isbn){
let ISBN // private attribute
function checkISBN(x){ // private method
x=x+''
if(x.length!==13)
return false
return true
}
this.setISBN=function(){
if(!checkISBN(isbn))
throw Error('Incorrect ISBN number!')
ISBN=isbn
}
this.getISBN=function(){
console.log(`ISBN number is ${ISBN}`)
}
this.setISBN()
}
const book1 = new Book(1122334455667)
book1.ISBN = 987
book1.getISBN() // ISBN number is 1122334455667
In the above example, we got the result we expected ie 123. But you might be thinking what does this line do book1.ISBN=987
?
This line adds a new variable in book1
's this
scope.
ie
The above pattern is good for creating private members, but it comes with a cost, which is memory. ie Every time we instantiate a new object of this Book
class, we create fresh new copies of ISBN
and checkISBN
bundled inside the closure of Book
. Hence there is wastage of memory. Therefore we should only make private attributes and methods when they are actually needed.
Now let's come to the second part of the article: private static members.
In the above example we used a private method checkISBN(x)
, you will notice that this method has nothing to do with individual objects. Only thing it does is to check the input x
and determine whether it is correct of not, thus there is no sense in making its seperate copy whenever a new object is instantiated.
And therefore we need the concept of private static members.
A static member is a member which belongs to the class, not the objects. ie There is only a single copy of member which is created when the class is defined. No matter how much objects are instantiated, there will only on copy of the member residing in the memory.
Before creating a private static member, lets create a public static member of the class, which is very easy.
const Book = function(isbn){
Book.getLibrary()
}
Book.getLibrary = function(){
console.log('This book belongs to Oxford library.')
}
const book1 = new Book(123) // This book belongs to Oxford library.
To add a public static member we have to simply add the member in class's namespace.
Now, lets make a private static member, which is quite tricky.
Suppose we have to design a Book
class, which will have a private static attribute called booksCreated
which is initally set to zero and whenever a new book is instantiated, this variable must increment by one. We must ensure that it is kept private because we don't want it to be manipulated from outside of the class.
Here we will use closures along with IIFE (Immediately Invoked Function Expression).
const Book = (function(){
let booksCreated = 0 // private static attribute
return function(){
booksCreated++
this.getNumberOfBooks=function(){
return booksCreated
}
}
})()
const b1 = new Book()
const b2 = new Book()
const b3 = new Book()
console.log(b3.getNumberOfBooks()) // 3
console.log(b1.getNumberOfBooks()) // 3
Top comments (0)