1. Introduction
Getters and setters (accessor properties) let you define object or class properties that run custom logic when read or assigned, while still being used with plain property syntax (obj.prop, not obj.prop()). They are commonly used to validate input on write, compute a derived value on read (such as converting Celsius to Fahrenheit), or add side effects like logging, all without changing how the property appears to the caller.
Cricket analogy: Think of a scoreboard displaying a batter's run rate — the board doesn't store it directly, it recomputes it from runs and overs each time you glance at it, the way Virat Kohli's strike rate recalculates automatically after each ball without anyone manually updating a stored number.
2. Syntax
class ClassName {
#value;
get propertyName() {
return this.#value; // runs on `obj.propertyName`
}
set propertyName(newValue) {
// validate / transform newValue
this.#value = newValue; // runs on `obj.propertyName = x`
}
}3. Explanation
A get accessor is invoked automatically whenever the property is read (obj.prop), and a set accessor is invoked automatically whenever it is assigned (obj.prop = value) — no parentheses are used at the call site, even though a function actually runs. This makes getters and setters transparent to consumers: code can be refactored from a plain field to a computed accessor without breaking any calling code.
Cricket analogy: A commentator says 'Rohit Sharma's average' without ever calling a formula out loud — the broadcast system silently runs the calculation behind the scenes whenever the stat is mentioned, just as obj.prop triggers a getter without the caller writing obj.prop().
Getters and setters are commonly paired with a private backing field (#value) so the public accessor name can differ from — or fully control access to — the internal storage. A getter defined without a matching setter makes a property effectively read-only from the outside; assigning to it in non-strict mode silently fails, and in strict mode (including inside ES modules and classes) throws a TypeError.
Cricket analogy: A player's official contract value (#salary) stays locked in a private file, while the public net-worth figure fans see is a controlled getter — without a setter, journalists can view it but can't edit it, and trying to would just be rejected outright, like strict mode's TypeError.
Getters and setters LOOK like ordinary properties from the caller's side (t.fahrenheit, not t.fahrenheit()), which can be surprising — accessing what appears to be a simple field may actually execute arbitrary logic, throw an exception, or have side effects. Always check for get/set declarations before assuming a property access is 'free' of computation.
4. Example
class Temperature {
#celsius;
constructor(celsius) {
this.#celsius = celsius;
}
get fahrenheit() {
return this.#celsius * 9 / 5 + 32;
}
set fahrenheit(value) {
this.#celsius = (value - 32) * 5 / 9;
}
get celsius() {
return this.#celsius;
}
set celsius(value) {
if (typeof value !== "number") throw new TypeError("Must be a number");
this.#celsius = value;
}
}
const t = new Temperature(25);
console.log(t.fahrenheit);
t.fahrenheit = 98.6;
console.log(t.celsius);
console.log(typeof Object.getOwnPropertyDescriptor(Temperature.prototype, "celsius").get);
try {
t.celsius = "hot";
} catch (e) {
console.log(e instanceof TypeError);
}
console.log(t.celsius);5. Output
77
37
function
true
376. Key Takeaways
get/setdefine accessor properties that run code but are accessed like plain fields, without parentheses.- A getter without a matching setter makes the property effectively read-only from outside the class.
- Getters and setters are commonly backed by a private
#fieldto fully control internal state. - Setters are the natural place to add validation logic, throwing errors for invalid assignments.
- Accessors are visible on the class prototype and can be inspected with
Object.getOwnPropertyDescriptor().
Practice what you learned
1. How is a getter named `fahrenheit` invoked from outside the class?
2. What happens if you assign to a property that has a `get` accessor but no matching `set` accessor, in strict mode?
3. In the Temperature example, why does `t.celsius` remain 37 after the failed assignment `t.celsius = "hot"`?
4. Why are getters and setters considered potentially surprising to code readers?
5. What backing storage pattern is typically paired with getters and setters to fully control access to internal state?
Was this page helpful?
You May Also Like
Classes in JavaScript
How ES6 class syntax provides a cleaner, structured way to create objects and implement object-oriented patterns on top of JavaScript's prototype system.
Encapsulation in JavaScript
How JavaScript hides internal object state using ES2022 private class fields (`#field`) and the older underscore naming convention.
Objects in JavaScript
Learn how to create, access, and modify JavaScript objects, and understand why objects behave as reference types.
Prototypes and Prototypal Inheritance in JavaScript
The mechanism underlying every JavaScript object: how property lookups walk the prototype chain, and how `prototype`, `__proto__`, and `Object.getPrototypeOf` relate.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics