Table of contents
1.
Introduction
2.
Working of Encapsulation in JavaScript  
2.1.
Using Closures for Encapsulation  
2.2.
Using Classes for Encapsulation  
2.3.
Why Encapsulation Matters  
3.
Ways to Achieve Encapsulation in JavaScript  
3.1.
1. Using Closures  
3.2.
2. Using Classes with Private Fields  
3.3.
3. Using Modules  
4.
Points to Keep in Mind for Achieving Effective Encapsulation in JavaScript  
4.1.
1. Use Private Fields for Data Protection  
4.2.
2. Avoid Over-Encapsulation  
4.3.
3. Use Getters & Setters for Controlled Access  
4.4.
4. Keep Encapsulation Consistent Across Your Codebase  
4.5.
5. Test Your Encapsulated Code Thoroughly  
5.
Benefits of Encapsulation in JavaScript
6.
Frequently Asked Questions
6.1.
What is encapsulation in JavaScript?
6.2.
How do closures help in encapsulation?
6.3.
What is the difference between closures and class-based encapsulation?
7.
Conclusion
Last Updated: Feb 15, 2025
Easy

What is Encapsulation in Javascript?

Author Pallavi singh
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Encapsulation in JavaScript is a fundamental concept in object-oriented programming that helps in hiding data and restricting direct access to it. This is achieved using closures, private variables, or ES6 classes with private fields (#). Encapsulation improves code security, maintainability, and modularity by controlling how data is accessed and modified.

What is Encapsulation in Javascript?

In this article, you will learn the importance of encapsulation, different ways to implement it in JavaScript, and how it enhances code structure.

Working of Encapsulation in JavaScript  

Encapsulation in JavaScript is all about controlling how data is accessed & modified. It ensures that sensitive data is not exposed directly & can only be changed through specific methods. This makes your code more secure & less prone to errors.  

In JavaScript, encapsulation is achieved using closures & classes. Let’s understand it step by step.  

Using Closures for Encapsulation  

A closure is a function that has access to its own scope, the outer function’s scope, & the global scope. This makes it a great tool for encapsulation. For example:  

function createCounter() {
    let count = 0; // This variable is "encapsulated"

    return {
        increment: function() {
            count++;
            console.log(count);
        },
        decrement: function() {
            count--;
            console.log(count);
        },
        getCount: function() {
            return count;
        }
    };
}

const counter = createCounter();
counter.increment(); 
counter.increment(); 
counter.decrement(); 
console.log(counter.getCount()); 
You can also try this code with Online Javascript Compiler
Run Code

 

Output

1
2
1
1

 

In this example, the `count` variable is encapsulated inside the `createCounter` function. It cannot be accessed directly from outside. The only way to interact with it is through the ‘increment’, ‘decrement’, & ‘getCount’ methods.  

Using Classes for Encapsulation  

JavaScript classes provide a more structured way to achieve encapsulation. By using private fields (introduced in ES2022), you can hide data from outside access. Let’s see how:  

class Counter {
    count = 0; // Private field

    increment() {
        this.count++;
        console.log(this.count);
    }

    decrement() {
        this.count--;
        console.log(this.count);
    }

    getCount() {
        return this.count;
    }
}

const counter = new Counter();
counter.increment();
counter.increment(); 
counter.decrement(); 
console.log(counter.getCount()); 
You can also try this code with Online Javascript Compiler
Run Code

 

Output

1
2
1
1

 

In this example, the `count` variable is private & cannot be accessed directly outside the class. The methods 'increment`, `decrement', & `getCount` are the only ways to interact with it.  

Why Encapsulation Matters  

1. Security: Prevents unauthorized access to sensitive data.  
 

2. Maintainability: Makes code easier to manage & debug.  
 

3. Flexibility: Allows you to change the internal implementation without affecting the rest of the code.  

Ways to Achieve Encapsulation in JavaScript  

Encapsulation in JavaScript can be achieved in multiple ways. Each method has its own use case & benefits. Let’s discuss the most common techniques:  

1. Using Closures  

Closures are one of the oldest & most effective ways to achieve encapsulation in JavaScript. By defining variables inside a function & returning methods that interact with those variables, you can create a private scope.  

For example:  

function createBankAccount() {
    let balance = 0; // Encapsulated variable

    return {
        deposit: function(amount) {
            if (amount > 0) {
                balance += amount;
                console.log(`Deposited: ${amount}, New Balance: ${balance}`);
            } else {
                console.log("Invalid deposit amount");
            }
        },
        withdraw: function(amount) {
            if (amount > 0 && amount <= balance) {
                balance -= amount;
                console.log(`Withdrawn: ${amount}, New Balance: ${balance}`);
            } else {
                console.log("Invalid withdrawal amount");
            }
        },
        getBalance: function() {
            return balance;
        }
    };
}
const account = createBankAccount();
account.deposit(500); // Output: Deposited: 500, New Balance: 500
account.withdraw(200); // Output: Withdrawn: 200, New Balance: 300
console.log(account.getBalance()); 
You can also try this code with Online Javascript Compiler
Run Code

 

Output

300

 

In this example, the `balance` variable is encapsulated within the `createBankAccount` function. It cannot be accessed directly from outside. The only way to interact with it is through the `deposit`, ‘withdraw', & ‘getBalance’ methods.  

2. Using Classes with Private Fields  

With the introduction of private fields in ES2022, encapsulation in JavaScript became even more straightforward. Private fields are declared using the `` symbol & can only be accessed within the class.  

For example: 

class BankAccount {
    balance = 0; // Private field

    deposit(amount) {
        if (amount > 0) {
            this.balance += amount;
            console.log(`Deposited: ${amount}, New Balance: ${this.balance}`);
        } else {
            console.log("Invalid deposit amount");
        }
    }

    withdraw(amount) {
        if (amount > 0 && amount <= this.balance) {
            this.balance -= amount;
            console.log(`Withdrawn: ${amount}, New Balance: ${this.balance}`);
        } else {
            console.log("Invalid withdrawal amount");
        }
    }

    getBalance() {
        return this.balance;
    }
}

const account = new BankAccount();
account.deposit(1000); // Output: Deposited: 1000, New Balance: 1000
account.withdraw(300); // Output: Withdrawn: 300, New Balance: 700
console.log(account.getBalance()); 
You can also try this code with Online Javascript Compiler
Run Code


Output: 

700

 

In this example, the `balance` variable is private & cannot be accessed directly outside the class. The methods `deposit`, `withdraw`, & `getBalance` are the only ways to interact with it.  

3. Using Modules  

JavaScript modules allow you to encapsulate code by splitting it into separate files. Each module has its own scope, & you can control what is exposed to other modules using `export` & `import`.  

For example:  

bankAccount.js  

let balance = 0; // Encapsulated variable

export function deposit(amount) {
    if (amount > 0) {
        balance += amount;
        console.log(`Deposited: ${amount}, New Balance: ${balance}`);
    } else {
        console.log("Invalid deposit amount");
    }
}

export function withdraw(amount) {
    if (amount > 0 && amount <= balance) {
        balance -= amount;
        console.log(`Withdrawn: ${amount}, New Balance: ${balance}`);
    } else {
        console.log("Invalid withdrawal amount");
    }
}

export function getBalance() {
    return balance;
}

main.js  
import { deposit, withdraw, getBalance } from './bankAccount.js';

deposit(500); // Output: Deposited: 500, New Balance: 500
withdraw(200); // Output: Withdrawn: 200, New Balance: 300
console.log(getBalance()); 
You can also try this code with Online Javascript Compiler
Run Code

 

Output: 

300

 

In this example, the `balance` variable is encapsulated within the `bankAccount.js` module. It cannot be accessed directly from outside the module. The only way to interact with it is through the `deposit`, `withdraw`, & `getBalance` functions.  

Points to Keep in Mind for Achieving Effective Encapsulation in JavaScript  

Encapsulation is a powerful concept, but it requires careful implementation to be effective. Let’s take a look at some of the important points to keep in mind when working with encapsulation in JavaScript:  

1. Use Private Fields for Data Protection  

Private fields (introduced in ES2022) are the most secure way to encapsulate data in JavaScript. They ensure that sensitive data cannot be accessed or modified directly from outside the class.  

Example:  

class User {
    password; // Private field

    constructor(username, password) {
        this.username = username;
        this.password = password;
    }

    validatePassword(inputPassword) {
        return inputPassword === this.password;
    }
}

const user = new User("john_doe", "secure123");
console.log(user.validatePassword("wrong")); 
console.log(user.validatePassword("secure123")); 
You can also try this code with Online Javascript Compiler
Run Code

 

Output: 

false
true

 

In this example, the `password` field is private & cannot be accessed directly. The `validatePassword` method is the only way to interact with it.  

2. Avoid Over-Encapsulation  

While encapsulation is important, over-encapsulation can make your code unnecessarily complex. Only encapsulate data that needs to be protected or hidden.  

Example:  

class Product {
    constructor(name, price) {
        this.name = name; // No need to encapsulate
        this.price = price; // No need to encapsulate
    }
}
const product = new Product("Laptop", 1000);
console.log(product.name); 
console.log(product.price); 
You can also try this code with Online Javascript Compiler
Run Code


Output: 

Laptop
1000

 

In this example, the `name` & `price` fields do not need to be encapsulated because they are not sensitive or prone to misuse.  

3. Use Getters & Setters for Controlled Access  

Getters & setters allow you to control how data is accessed & modified. They are especially useful when you need to add validation or logic before updating a value.  

Example:  

class Temperature {
    celsius; // Private field

    constructor(celsius) {
        this.celsius = celsius;
    }
    get celsius() {
        return this.celsius;
    }
    set celsius(value) {
        if (value < -273.15) {
            console.log("Temperature cannot be below absolute zero");
        } else {
            this.celsius = value;
        }
    }
}
const temp = new Temperature(25);
console.log(temp.celsius); 
temp.celsius = -300; 
console.log(temp.celsius); 
You can also try this code with Online Javascript Compiler
Run Code


Output: 

25
Temperature cannot be below absolute zero
25


In this example, the `celsius` field is encapsulated, & the `set celsius` method ensures that the temperature cannot be set below absolute zero.  

4. Keep Encapsulation Consistent Across Your Codebase  

Consistency is key to maintaining clean & readable code. If you decide to use encapsulation for certain data, apply the same approach throughout your codebase.  

Example:  

class Employee {
    salary; // Private field

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

    getSalary() {
        return this.salary;
    }
}

class Manager extends Employee {
    constructor(name, salary, bonus) {
        super(name, salary);
        this.bonus = bonus;
    }

    getTotalSalary() {
        return this.getSalary() + this.bonus;
    }
}

const manager = new Manager("Alice", 5000, 1000);
console.log(manager.getTotalSalary()); 
You can also try this code with Online Javascript Compiler
Run Code

 

Output

6000

 

In this example, the `salary` field is encapsulated in the `Employee` class, & the same approach is used in the `Manager` class.  

5. Test Your Encapsulated Code Thoroughly  

Encapsulated code can sometimes be harder to debug, so it’s important to test it thoroughly. Use unit tests to ensure that your encapsulated methods work as expected.  

Example: 

class Calculator {
    result = 0; // Private field

    add(number) {
        this.result += number;
    }
    subtract(number) {
        this.result -= number;
    }

    getResult() {
        return this.result;
    }
}
// Unit Test
const calculator = new Calculator();
calculator.add(10);
calculator.subtract(4);
console.log(calculator.getResult()); 
You can also try this code with Online Javascript Compiler
Run Code

 

Output

6
You can also try this code with Online Javascript Compiler
Run Code


In this example, the `result` field is encapsulated, & the `add`, `subtract`, & `getResult` methods are tested to ensure they work correctly.  

Benefits of Encapsulation in JavaScript

1. Data Protection

Encapsulation prevents direct modification of data, reducing unintended bugs.

2. Improved Code Maintainability

Encapsulated code is easier to manage and update.

3. Better Data Control

Encapsulation allows controlled access to data through getter and setter methods.

4. Encourages Modularity

Encapsulation helps in creating modular and reusable code components.

Frequently Asked Questions

What is encapsulation in JavaScript?

Encapsulation is the practice of keeping certain parts of code private to prevent direct modification and ensure data security.

How do closures help in encapsulation?

Closures create private variables inside a function, restricting direct access to them while providing controlled interaction through methods.

What is the difference between closures and class-based encapsulation?

Closures use functions to create private variables, while classes use the # symbol to define private fields within a class structure.

Conclusion

In this article, we learned encapsulation in JavaScript, a key concept in object-oriented programming that helps in data protection and code organization. Encapsulation allows developers to restrict direct access to object properties using closures, private fields, and getter/setter methods. By applying encapsulation, we can write more secure, maintainable, and modular JavaScript code, improving overall application efficiency.

Live masterclass