Skip to main content

JavaScript Classes

JavaScript Private Fields

Written by Published

A field starting with a hash is private and cannot be read from outside the class.

The underscore convention was only ever a hint; nothing enforced it.

A # field is genuinely inaccessible from outside.

Example

Example

javascript

class Account {
  #balance = 100;

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

console.log(new Account().getBalance());

The balance is readable through the method but not directly.

What is a Private Field?

A name beginning with # is private to the class body.

Reading it from outside is a syntax error, not just a bad idea.

Methods can be private too.

Syntax

Syntax

javascript

class Name {
  #secret = value;

  #privateMethod() {}
}

The # is part of the name, not an operator.

It Really Is Private

Unlike the underscore convention, this cannot be worked around.

It does not appear in Object.keys either.

Example

Example

javascript

class Account {
  #balance = 100;
  name = "current";
}

const account = new Account();

console.log(Object.keys(account).join(","));

Only the public field is listed.

Controlled Access

Expose exactly what you want, and nothing more.

Example

Example

javascript

class Account {
  #balance = 0;

  deposit(amount) {
    if (amount > 0) {
      this.#balance += amount;
    }
    return this.#balance;
  }
}

const account = new Account();
account.deposit(-50);

console.log(account.deposit(100));

The negative deposit was refused and the balance stayed safe.

Private Methods

Helpers that are nobody else's business can be hidden too.

Example

Example

javascript

class Order {
  #price = 100;

  #tax() {
    return this.#price * 0.2;
  }

  total() {
    return this.#price + this.#tax();
  }
}

console.log(new Order().total());

The output is 120, and #tax cannot be called from outside.

The Old Underscore Convention

An underscore says please do not touch this, but nothing stops you.

You will still see it constantly in older code.

Example

Example

javascript

class Account {
  constructor() {
    this._balance = 100;
  }
}

const account = new Account();
account._balance = 999999;

console.log(account._balance);

Nothing prevented the change, which is exactly the problem.

Private Fields Are Not Inherited

A child class cannot reach its parent's private fields.

That is the point: private means private to that class body.

Example

Example

javascript

class Parent {
  #secret = "hidden";

  reveal() {
    return this.#secret;
  }
}

class Child extends Parent {}

console.log(new Child().reveal());

The child can use the public method but not the field itself.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript Private Fields</title>
</head>
<body>

  <h1>Private Fields</h1>

  <p id="out"></p>

  <script>
    class Account {
      #balance = 0;

      constructor(owner) {
        this.owner = owner;
      }

      deposit(amount) {
        if (amount <= 0) return this.#balance;
        this.#balance += amount;
        return this.#balance;
      }

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

    const account = new Account("Ada");
    account.deposit(100);
    account.deposit(-500);

    document.getElementById("out").textContent =
      account.owner + " has " + account.balance;
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try reaching in:

Add account.#balance = 999 and see the syntax error.

Important Points

  • A # name is private to the class body.
  • It cannot be read or written from outside.
  • Private fields do not appear in Object.keys.
  • Methods can be private too.
  • A child class cannot access a parent's private fields.

Conclusion

Private fields turn encapsulation from a convention into a rule.

Exposing a method or a getter gives you control over how data is reached.

This is the modern replacement for the underscore prefix.