Getters and setters
Sometimes a property should not just store a value but do something: compute a result on the fly or check what is being written into it. Getters and setters exist for this — methods that look like ordinary properties from the outside.
A getter
The get keyword before a method turns it into a getter. You access it like a property, without parentheses, and it returns the method's result:
class User {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
const user = new User('Anna', 'Smith');
console.log(user.fullName); // Anna SmithA computed value is always up to date
A getter computes the value on every access, so it never goes stale when the source data changes:
class Cart {
items = [];
get total() {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
}
const cart = new Cart();
cart.items.push({ title: 'Tea', price: 5 });
cart.items.push({ title: 'Coffee', price: 12 });
console.log(cart.total); // 17There is no need to keep the total in a separate property and remember to recalculate it.
A setter
The set keyword declares a setter — a method that runs when the property is written to. The written value arrives in its parameter:
class User {
set name(value) {
this.firstName = value.trim();
}
}
const user = new User();
user.name = ' Oleg ';
console.log(user.firstName); // OlegValidating a value
The main benefit of a setter is validation. Together with a private field it will not let an invalid value into the object:
class Product {
#price = 0;
get price() {
return this.#price;
}
set price(value) {
if (value < 0) {
throw new Error('Price cannot be negative');
}
this.#price = value;
}
}
const product = new Product();
product.price = 25;
console.log(product.price); // 25Writing product.price = -5 would throw an error, and the wrong price would never reach the object.
A read-only property
If you declare a getter without a setter, the property can only be read. Writing to it does not work: in an ordinary script it is silently ignored, and in modules and strict mode it throws a TypeError:
class Circle {
constructor(radius) {
this.radius = radius;
}
get diameter() {
return this.radius * 2;
}
}
const circle = new Circle(5);
circle.diameter = 100;
console.log(circle.diameter); // 10Common mistake
Inside a setter you must not write the value to a property with the same name. Such a write calls the setter again, which calls itself again, and the program crashes with a stack overflow error:
class User {
set name(value) {
this.name = value; // the setter calls itself forever
}
}Store the value in a field with a different name — usually a private one: this.#name = value.