JavaScript Encapsulation

In this chapter, we will learn about JavaScript encapsulation. Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It refers to the practice of bundling data and methods that operate on that data within a single unit or class and restricting access to some of the object’s components. We will cover:

  • What is Encapsulation?
  • Why Use Encapsulation?
  • Implementing Encapsulation
  • Using Private Fields
  • Using Getters and Setters
  • Simple Programs using Encapsulation

What is Encapsulation?

Encapsulation is the practice of keeping the internal state of an object hidden from the outside world. This is done by restricting direct access to some of an object’s components and only exposing a controlled interface for interacting with the object.

Why Use Encapsulation?

Encapsulation provides several benefits:

  • Data Protection: Prevents external code from directly modifying the internal state of an object, reducing the risk of unintended side effects and bugs.
  • Modularity: Encourages a modular design by bundling related data and methods together.
  • Maintainability: Makes code easier to maintain and understand by providing a clear interface for interacting with objects.
  • Abstraction: Hides the internal implementation details and exposes only the necessary functionality.

Implementing Encapsulation

Encapsulation can be implemented using private fields, getters, and setters.

Using Private Fields

In JavaScript, you can use the # symbol to create private fields within a class. Private fields are only accessible within the class and are not exposed to the outside world.

Example

class Person {
  // Private fields
  #firstName;
  #lastName;

  constructor(firstName, lastName) {
    this.#firstName = firstName;
    this.#lastName = lastName;
  }

  // Public method to get full name
  getFullName() {
    return `${this.#firstName} ${this.#lastName}`;
  }
}

let person = new Person("Ramesh", "Fadatare");
console.log(person.getFullName());
console.log(person.#firstName); // This will cause an error

Output:

Ramesh Fadatare
SyntaxError: Private field '#firstName' must be declared in an enclosing class

Using Getters and Setters

Getters and setters provide a controlled way to access and modify the properties of an object. They allow you to add custom logic and validation.

Example

class Person {
  #firstName;
  #lastName;

  constructor(firstName, lastName) {
    this.#firstName = firstName;
    this.#lastName = lastName;
  }

  // Getter for full name
  get fullName() {
    return `${this.#firstName} ${this.#lastName}`;
  }

  // Setter for full name
  set fullName(name) {
    let parts = name.split(' ');
    this.#firstName = parts[0];
    this.#lastName = parts[1];
  }
}

let person = new Person("Ramesh", "Fadatare");
console.log(person.fullName);

person.fullName = "Neha Sharma";
console.log(person.fullName);

Output:

Ramesh Fadatare
Neha Sharma

Simple Programs using Encapsulation

Program 1: Bank Account with Encapsulation

class BankAccount {
  #balance;

  constructor(accountNumber, accountHolder, balance) {
    this.accountNumber = accountNumber;
    this.accountHolder = accountHolder;
    this.#balance = balance;
  }

  // Getter for balance
  get balance() {
    return this.#balance;
  }

  // Method to deposit money
  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
    }
  }

  // Method to withdraw money
  withdraw(amount) {
    if (amount > 0 && amount <= this.#balance) {
      this.#balance -= amount;
    } else {
      console.log("Insufficient funds");
    }
  }
}

let account = new BankAccount("1234567890", "Rahul Sharma", 5000);
console.log("Initial Balance:", account.balance);

account.deposit(2000);
console.log("Balance after deposit:", account.balance);

account.withdraw(1000);
console.log("Balance after withdrawal:", account.balance);

account.withdraw(7000); // This should trigger insufficient funds message

Output:

Initial Balance: 5000
Balance after deposit: 7000
Balance after withdrawal: 6000
Insufficient funds

Program 2: Employee Management with Encapsulation

class Employee {
  #salary;

  constructor(name, position, salary) {
    this.name = name;
    this.position = position;
    this.#salary = salary;
  }

  // Getter for salary
  get salary() {
    return this.#salary;
  }

  // Setter for salary with validation
  set salary(amount) {
    if (amount > 0) {
      this.#salary = amount;
    } else {
      console.log("Salary must be a positive number");
    }
  }

  // Method to get employee details
  getDetails() {
    return `${this.name}, ${this.position}, Salary: ${this.#salary}`;
  }
}

let emp = new Employee("Neha Sharma", "Manager", 80000);
console.log(emp.getDetails());

emp.salary = 90000; // Valid update
console.log(emp.getDetails());

emp.salary = -5000; // Invalid update

Output:

Neha Sharma, Manager, Salary: 80000
Neha Sharma, Manager, Salary: 90000
Salary must be a positive number

Program 3: Student Grades with Encapsulation

class Student {
  #grades;

  constructor(name, grades) {
    this.name = name;
    this.#grades = grades;
  }

  // Getter for grades
  get grades() {
    return this.#grades;
  }

  // Setter for grades with validation
  set grades(newGrades) {
    if (Array.isArray(newGrades) && newGrades.every(grade => grade >= 0 && grade <= 100)) {
      this.#grades = newGrades;
    } else {
      console.log("All grades should be between 0 and 100");
    }
  }

  // Getter for average grade
  get averageGrade() {
    let sum = this.#grades.reduce((acc, grade) => acc + grade, 0);
    return sum / this.#grades.length;
  }
}

let student = new Student("Priya", [85, 90, 78]);
console.log("Initial Grades:", student.grades);
console.log("Average Grade:", student.averageGrade);

student.grades = [88, 92, 80]; // Valid update
console.log("Updated Grades:", student.grades);
console.log("New Average Grade:", student.averageGrade);

student.grades = [105, 90, 78]; // Invalid update

Output:

Initial Grades: [ 85, 90, 78 ]
Average Grade: 84.33333333333333
Updated Grades: [ 88, 92, 80 ]
New Average Grade: 86.66666666666667
All grades should be between 0 and 100

Conclusion

In this chapter, you learned about JavaScript encapsulation, including its benefits and how to implement it using private fields, getters, and setters. We also provided various use cases with simple programs to demonstrate the usage of encapsulation. Encapsulation is a fundamental concept in OOP that helps protect the internal state of objects and promotes better code organization.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top