Lets Encapsulate : Designing an ATM

In this article we would cover one of the fundamental concept of OOP, Encapsulation.

Encapsulation is the practice of bundling the data (variables) and methods (functions) that operate on the data into a single unit, or class, and restricting access to some of the object's components.

Lets design an ATM.

 class ATM {
  constructor(pin,initialBalance,transactionHistory,accountHolderName,bankName,atmLocation,maxWithdrawalLimit)
   {
    /////////////instance fields///////////////
    //private field
    this.#pin = pin;
    //protected fields
    this._balance = initialBalance;
    this._transactionHistory = transactionHistory;
    //public field
    this.maxWithdrawalLimit = maxWithdrawalLimit;
    this.status = 'active';
  }
}

Instance Fields

Fields declared in the constructor using this are instance-specific. Each instance of the class gets its own copy of these fields.

Private Fields

Private fields are variables that are not accessible outside the class. They can only be accessed through methods within the same class. In modern JavaScript (ES6+), private fields can be defined using the # syntax.

Now lets see how to declare a private method:

//private method
#authenticate(enteredPin) {
    return this.#pin === enteredPin;
  }

Are Private Fields a part of Prototype Chain?

When you declare a private field using the # syntax, each instance of the class gets its own copy of that field. These fields are not shared across instances, and they are not part of the prototype chain. This means that private fields cannot be accessed or modified from outside the class, ensuring strict encapsulation.

Protected Fields

JavaScript doesn't have built-in support for protected fields in the same way as some other languages. However, you can simulate protected fields by using conventions or closures.

Public Fields

Public fields are accessible from outside the class. In JavaScript, public fields are simply defined in the constructor or directly in the class body.

Prototype Methods

These methods are shared among all instances of the class, which saves memory and ensures that the method behavior is consistent across instances.

//public methods
//these methods are declared on the prototype to save memory
 deposit(amount) {
    if (amount > 0) {
      this._balance += amount - this.transactionFees;
      this._transactionHistory.push({ transactionType: 'Deposit', amount });
      console.log(
        `Deposited amount : ${amount} New balance : ${this._balance}`
      );
    } else {
      console.log(`Deposited amount must be positive`);
    }
  }

Prototype Fields

Fields can be manually added to the prototype, although this is less common than adding methods. These fields are shared across all instances of the class.

Example:

// Adding a public field to the prototype
ATM.prototype.globalATMId = "ATM001"; // Public prototype field

Creating an ATM object:

 const atm = new ATM(2980,20000,[],'Sarah Gomes','CSDC International Bank','Mumbai',100000);
 atm.deposit(3000);

Do checkout the source code at https://github.com/Carolin16/JS-Projects/tree/main