#field

Fields and methods prefixed with # are private: only code inside the class can access them.

On this page

Example

#
JavaScript
class FuelTank {
  #fuel = 10

  use(amount) {
    if (amount > this.#fuel) return false
    this.#fuel -= amount
    return true
  }

  get fuel() {
    return this.#fuel
  }
}

const tank = new FuelTank()

console.log(tank.use(3))
console.log(tank.use(20))
console.log(tank.fuel)
console.log(tank)
console.log(Object.keys(tank))
Console
true
false
7
FuelTank {}
[]

Definition and usage

#

A field or method name starting with # marks a private member. It can only be used inside the body of the class where it was declared. Accessing obj.#field from outside is a syntax error, reported before the code even runs.

This is real privacy, not just a convention, unlike the underscore _field naming pattern. Private fields don’t show up in Object.keys(), JSON.stringify(), or a for...in loop, and code outside the class can’t read or change them. The class alone decides what it exposes, for example through methods or getters.

A private field has to be declared in the class body, such as #coins = 0 or just #password, before it’s used. Methods (#validate()), getters, and static members can be private too. Derived classes can’t see the parent’s private fields, and the operator #field in obj checks whether an object has that private field.

Syntax

#
Syntax
class Name {
  #field = value
  static #staticField = value

  #method() {}

  read() {
    return this.#field
  }

  static isName(obj) {
    return #field in obj
  }
}

More examples

#
A private method
JavaScript
class Account {
  #password

  constructor(login, password) {
    this.login = login
    this.#password = this.#hash(password)
  }

  #hash(text) {
    return [...text].reverse().join('')
  }

  checkPassword(attempt) {
    return this.#hash(attempt) === this.#password
  }
}

const account = new Account('emma', 'secret123')

console.log(account.checkPassword('secret123'))
console.log(account.checkPassword('password'))
console.log(JSON.stringify(account))
Console
true
false
{"login":"emma"}

Reversing the string is just an illustration. Real passwords are secured with hash functions on the server, not in the browser.

Checking with #field in
JavaScript
class Badge {
  #id

  constructor(id) {
    this.#id = id
  }

  static isBadge(value) {
    return #id in value
  }
}

console.log(Badge.isBadge(new Badge(7)))
console.log(Badge.isBadge({ id: 7 }))
Console
true
false
Pitfall: _field is only a convention
JavaScript
class OldWallet {
  constructor() {
    this._coins = 100
  }
}

class NewWallet {
  #coins = 100
}

const oldWallet = new OldWallet()
oldWallet._coins = 1000000

console.log(oldWallet)
console.log(new NewWallet())
Console
OldWallet { _coins: 1000000 }
NewWallet {}

The underscore only suggests the field shouldn’t be touched, but any code can change it. The #coins field can’t even be read from outside.

Browser support

#

Widely available · since 2021

Works in all modern browsers, phones included. You can use it without worry.

  • Chrome
  • Edge
  • Firefox
  • Safari

Good practices

#
  • Declare every private field in the class body before you assign it a value. Just writing this.#field = x in the constructor, without a declaration, is a syntax error.
  • Private fields don’t make it into JSON.stringify() or a { ...obj } copy. If the data needs to reach an API, add a toJSON() method that returns what you want to send.
  • Privacy applies to the class, not to a single object. A class method can read #field on another instance of the same class, for example when comparing a.#id === b.#id.

Related entries

#

Spotted a mistake or missing an example? Write to us.