#field
Fields and methods prefixed with # are private: only code inside the class can access them.
Example
#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))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
#class Name {
#field = value
static #staticField = value
#method() {}
read() {
return this.#field
}
static isName(obj) {
return #field in obj
}
}More examples
#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))Reversing the string is just an illustration. Real passwords are secured with hash functions on the server, not in the browser.
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 }))class OldWallet {
constructor() {
this._coins = 100
}
}
class NewWallet {
#coins = 100
}
const oldWallet = new OldWallet()
oldWallet._coins = 1000000
console.log(oldWallet)
console.log(new 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 = xin 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 atoJSON()method that returns what you want to send. - Privacy applies to the class, not to a single object. A class method can read
#fieldon another instance of the same class, for example when comparinga.#id === b.#id.
Related entries
#- classDefines a class: a template for creating objects that share the same fields and methods.
- get / setProperties computed on read (get) and handled on write (set).
- staticMarks a field or method as belonging to the class itself, not to instances created with new.
- extendsCreates a derived class that inherits another class’s methods and can extend or override them.
- WeakMapA map with objects as keys that doesn’t keep them in memory: the entry disappears along with the unused object.
- SymbolA primitive type for creating unique identifiers, such as property keys that never collide with others.
Spotted a mistake or missing an example? Write to us.