JavaScript private methods are class methods that can only be accessed from within the class that declares them. They help keep internal operations hidden from outside code and provide a clear way to implement encapsulation. A private method name starts with the # character, such as #calculateTotal().

Unlike a method whose name begins with an underscore, a true private method is enforced by the JavaScript language. Code outside the declaring class cannot call it, even when it has a reference to an instance. In this tutorial, you will learn how to declare, call, and use private instance methods, private static methods, and private accessors with practical examples.

1. What Is a Private Method in JavaScript?

A private method is a class method whose name begins with #. It is part of the class private elements system and is available only in the class body where it is declared. Private methods are useful for helper operations that should not be part of a class public API.

class User {
  #formatName(name) {
    return name.trim().toUpperCase();
  }

  getDisplayName(name) {
    return this.#formatName(name);
  }
}

const user = new User();

console.log(user.getDisplayName("  Alex  ")); // ALEX
// console.log(user.#formatName("Alex")); // SyntaxError

In this example, #formatName() is private. The public getDisplayName() method can call it, but outside code cannot access it directly. The commented line is intentionally invalid JavaScript; uncommenting it causes a syntax error.

2. Syntax of a Private Method

Declare a private method inside a class by placing # immediately before its name. Call it from an allowed location with this.#methodName().

class ClassName {
  #privateMethod() {
    // Internal implementation
  }

  publicMethod() {
    this.#privateMethod();
  }
}

The hash character is part of the private name. It is not a string prefix and cannot be replaced with bracket notation. A private method must be declared inside a class body; it cannot be declared as a private method on an ordinary object literal.

3. Calling a Private Instance Method

Most private methods are instance methods. A public method, constructor, getter, setter, or another private method in the same class can call them.

class Calculator {
  #addTax(price) {
    return price * 0.15;
  }

  getFinalPrice(price) {
    const tax = this.#addTax(price);
    return price + tax;
  }
}

const calculator = new Calculator();

console.log(calculator.getFinalPrice(100)); // 115
// calculator.#addTax(100); // SyntaxError

The class controls when its private calculation runs. The caller only needs to know about the public getFinalPrice() method, not the internal tax calculation.

4. Using Private Methods for Input Validation

A private method can keep validation logic out of a public method. This makes the public method easier to read and prevents callers from depending on internal validation details.

class Registration {
  #isValidEmail(email) {
    return typeof email === "string" &&
      email.includes("@") &&
      email.includes(".");
  }

  register(email) {
    if (!this.#isValidEmail(email)) {
      return "Please provide a valid email address.";
    }

    return "Registration completed for " + email;
  }
}

const form = new Registration();

console.log(form.register("alex@example.com"));
console.log(form.register("invalid-email"));

Here, register() is the public entry point. The helper method #isValidEmail() performs a simple format check. This example is for demonstrating encapsulation; production email validation should use the rules required by the application and usually confirm the address through a verification process.

5. Practical Example: Bank Account

Private methods are especially useful when a class needs to protect operations that maintain its internal state. In the following example, the balance is stored in a private field and a private method checks whether a withdrawal is allowed.

class BankAccount {
  #balance;

  constructor(initialBalance = 0) {
    this.#balance = initialBalance;
  }

  #hasEnoughBalance(amount) {
    return amount > 0 && amount <= this.#balance;
  }

  deposit(amount) {
    if (amount <= 0) {
      return "Deposit amount must be positive.";
    }

    this.#balance += amount;
    return "Deposit successful.";
  }

  withdraw(amount) {
    if (!this.#hasEnoughBalance(amount)) {
      return "Invalid amount or insufficient balance.";
    }

    this.#balance -= amount;
    return "Withdrawal successful.";
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(500);

console.log(account.withdraw(150)); // Withdrawal successful.
console.log(account.getBalance());  // 350
// account.#hasEnoughBalance(100); // SyntaxError

The private method #hasEnoughBalance() centralizes the withdrawal check. The public withdraw() method uses it before changing the balance. The private field protects the balance itself; the private method protects an internal operation.

6. Private Methods Can Call Other Private Methods

A class can contain multiple private methods, and one private method can call another. This is useful when a larger operation is divided into smaller internal steps.

class Report {
  #getHeader() {
    return "Monthly Sales Report";
  }

  #getFooter() {
    return "End of report";
  }

  #buildContent() {
    return this.#getHeader() + "\nSales: 250\n" + this.#getFooter();
  }

  print() {
    console.log(this.#buildContent());
  }
}

const report = new Report();
report.print();

Only print() is exposed as the public operation. The header, footer, and content-building methods remain implementation details.

7. Private Static Methods

A static method belongs to the class itself rather than to an individual instance. A private static method is declared with static followed by the private name. Call it through the class name from within the declaring class.

class Product {
  static #isValidCode(code) {
    return typeof code === "string" && code.length >= 4;
  }

  static create(code, name) {
    if (!Product.#isValidCode(code)) {
      throw new Error("Product code must contain at least four characters.");
    }

    return { code, name };
  }
}

const item = Product.create("P100", "Keyboard");
console.log(item);

// Product.#isValidCode("P100"); // SyntaxError

A private static method is suitable for class-level helper logic, such as validating a code before creating an object. It is not called through an instance. Using Product.#isValidCode() inside the declaring class also avoids confusion about the receiver of a static private method.

8. Private Getters and Setters

JavaScript also allows private accessor methods. A private getter or setter uses the same # naming syntax, with get or set. These accessors can be used internally by other class methods.

class Temperature {
  #celsius;

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

  get #fahrenheit() {
    return (this.#celsius * 9) / 5 + 32;
  }

  getFahrenheit() {
    return this.#fahrenheit;
  }
}

const temperature = new Temperature(25);
console.log(temperature.getFahrenheit()); // 77

The private getter #fahrenheit computes a value on demand. It is used inside the class by getFahrenheit() and is not available as a public property on the instance.

9. Private Methods and Inheritance

A subclass cannot directly access a private method declared by its parent class. Private names are scoped to the class that declares them. A child class can, however, use a public or protected-by-convention method that the parent class deliberately exposes. JavaScript does not have a built-in protected access modifier.

class BaseLogger {
  #write(message) {
    console.log("[LOG] " + message);
  }

  log(message) {
    this.#write(message);
  }
}

class AppLogger extends BaseLogger {
  start() {
    this.log("Application started");
    // this.#write("Started"); // SyntaxError: not declared in this class
  }
}

const logger = new AppLogger();
logger.start();

The subclass calls the inherited public log() method. The parent class keeps #write() private. This lets the parent control how logging is performed without giving subclasses direct access to its internal helper.

10. Checking Whether an Object Has a Private Method

Inside the class that declares a private method, the #name in object syntax can check whether an object has that private element. This is a private-brand check. It is useful when a method may receive an object that is not an instance carrying the class private elements.

class Validator {
  #run() {
    return "Validation ran.";
  }

  static canValidate(value) {
    return #run in value;
  }
}

const validator = new Validator();

console.log(Validator.canValidate(validator)); // true
console.log(Validator.canValidate({}));         // false

The private name can be used in this check only from within the class body where it is declared. It does not expose the method or allow outside code to call it.

11. Private Methods vs. Underscore Methods

You may see JavaScript methods named with a leading underscore, such as _calculateTotal(). The underscore is only a naming convention. It communicates that a method is intended for internal use, but it does not prevent outside code from calling it.

class Example {
  _internalByConvention() {
    return "This is still public.";
  }

  #actuallyPrivate() {
    return "This is private.";
  }

  run() {
    return this.#actuallyPrivate();
  }
}

const example = new Example();

console.log(example._internalByConvention()); // Works
console.log(example.run());                   // Works
// example.#actuallyPrivate();                // SyntaxError

Use an underscore when you only want to communicate intent or need a method to remain accessible to subclasses and external code. Use # when you need language-enforced privacy.

12. Important Rules and Common Mistakes

Keep these rules in mind when working with JavaScript private methods:

1. Declare private methods inside a class. A private name cannot be added dynamically to an object after the class has been defined.

2. Include the hash character. Write this.#calculate(), not this.calculate(), when calling a private method.

3. Do not use bracket notation. this["#calculate"] refers to a normal string-named property, not the private method.

4. Do not call private methods from outside. An expression such as instance.#calculate() outside the declaring class is a syntax error.

5. Private names are not inherited. A subclass cannot directly call a parent class private method, even on an object created by the parent class.

6. Private elements are not ordinary object properties. They are not listed by Object.keys() or Object.getOwnPropertyNames(), and they are not included by JSON.stringify().

7. Avoid overusing private methods. Keep a method public when it represents a useful operation that other code is expected to call.

Categorized in:

Javascript, JS Basic,