Language: EN

javascript-metodos-y-variables-privados

Private Methods and Variables in JavaScript

Encapsulation is a concept derived from object-oriented programming (OOP) that consists of hiding and protecting the internal details of a class

Encapsulation has two main aspects:

  • Hiding the internal state of objects: Objects can have private properties that are not directly accessible from outside the class.
  • Providing a public interface: The class can expose public methods that allow controlled interaction with its properties.

In other words, it is about protecting direct access to data and exposing only what is necessary for other parts of the program to interact with that class.

By hiding the internal state of objects and providing a controlled public interface, we ensure that our objects are more robust, easier to maintain, and less prone to errors.

Private Properties

In JavaScript, ES2022 introduced the private fields syntax. To do this, the property name is prefixed with #.

Properties that use this prefix are only accessible within the class in which they are defined (they cannot be accessed or modified from outside the class).

class Person {
    #name;

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

    getName() {
        return this.#name;
    }
}

const person1 = new Person("Juan");
// Correct access through a public method
console.log(person1.getName()); // "Juan"

// This will cause an error: "Cannot read private member"
console.log(person1.#name); // Error

In this example:

  • #name is a private property. It can only be accessed within the Person class.
  • getName() is a public method that allows access to the value of #name.

Private Methods

Methods can also be private. Like properties, they are defined with the # prefix:

class User {
    #secretKey;

    constructor(key) {
        this.#secretKey = key;
    }

    #showKey() {
        console.log(`The secret key is: ${this.#secretKey}`);
    }

    authenticate() {
        this.#showKey(); // Valid call from within the class
    }
}

const user1 = new User("12345");
user1.authenticate(); // The secret key is: 12345
// This will cause an error: "Cannot read private member"
// user1.#showKey(); // Error

In this example, #showKey() is a private method. It can only be called from within the class, not from outside.

Getters and Setters

Encapsulation fits very well with the use of getter and setter methods.

class Person {
    #age;

    constructor(age) {
        this.#age = age;
    }

    get age() {
        return this.#age;
    }

    set age(newAge) {
        if (newAge > 0) {
            this.#age = newAge;
        } else {
            console.log("Age must be positive.");
        }
    }
}

const person2 = new Person(25);
console.log(person2.age); // 25
person2.age = 30;         // Modifies age
console.log(person2.age); // 30
person2.age = -5;         // Age must be positive.

In this example:

  • The getter age allows access to the value of the private property #age.
  • The setter age allows modifying the value of #age only if it is a positive number.

Simple Example of Encapsulation

Let’s look at a basic example of how data can be encapsulated within a class:

class BankAccount {
    // Private property (accessed only from the class)
    #balance;

    constructor(initial) {
        this.#balance = initial;
    }

    // Public method to get the balance
    getBalance() {
        return this.#balance;
    }

    // Public method to deposit money
    deposit(amount) {
        if (amount > 0) {
            this.#balance += amount;
        } else {
            console.log("The amount must be positive.");
        }
    }

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

const account1 = new BankAccount(1000);
console.log(account1.getBalance());  // 1000
account1.deposit(500);
console.log(account1.getBalance());  // 1500
account1.withdraw(200);
console.log(account1.getBalance());  // 1300

In this example:

  • The property #balance is private and cannot be accessed directly from outside the class.
  • The methods deposit(), withdraw(), and getBalance() allow controlled interaction with the account balance.

We also could have used setter and getter methods, but this way we see another form with normal methods.