Private static members in Javascript
Tags: javascript, webdev, programming, adventofcode
Published: 2023-07-05 09:49:20

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 

```javascript
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:

```javascript
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
<kbd>
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ylyg6gcerqw334qckvjq.png)
</kbd>

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. 

<hr>

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.

```javascript 

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).

```javascript

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

```