JavaScript 32 🧬 Class getters and setters
Getters and setters are special functions used to get and set the values of an object’s properties. They allow you to control how properties are accessed and modified — providing encapsulation, validation, and computed properties.
A Quick Look at the Examples
// 1. Validation with getter/setter
class Person {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
set name(value) {
if (typeof value === 'string') {
this._name = value;
} else {
console.log('Name must be a string');
}
}
}
const person = new Person('Alice');
person.name = 'Bob';
console.log(person.name); // "Bob"
person.name = 123; // "Name must be a string"
// 2. Computed property with getter
class Circle {
constructor(radius) {
this._radius = radius;
}
get area() {
return Math.PI * this._radius ** 2;
}
}
const circle = new Circle(5);
console.log(circle.area); // 78.53981633974483
a. Getters and Setters Introduction
Getters and setters are special functions used to get and set the values of an object’s properties. They allow you to control how properties are accessed and modified — useful for encapsulation and validation.
Definitions
| Feature | Description |
|---|---|
| Getter | Function that returns the value of a property (get keyword) |
| Setter | Function that sets the value of a property (set keyword) |
Benefits of Using Getters and Setters
| Benefit | Description |
|---|---|
| Encapsulation | Hide the internal representation of an object’s data |
| Validation | Ensure only valid values are assigned to properties |
| Computed Properties | Define properties whose values are computed from other properties |
Basic Syntax
class MyClass {
constructor() {
this._value = 0; // Internal (convention: underscore prefix)
}
// Getter
get value() {
return this._value;
}
// Setter
set value(newValue) {
this._value = newValue;
}
}
Key points:
- Defined with
getandsetkeywords - Accessed like regular properties (no parentheses!)
- Getters take no parameters and must return a value
- Setters take exactly one parameter and must not return a value
Accessing Getter/Setter
const obj = new MyClass();
// Read — uses getter
console.log(obj.value); // Calls get value()
// Write — uses setter
obj.value = 42; // Calls set value(42)
Important: Getters and setters are accessed like regular properties — not like methods.
obj.value; // ✅ Calls getter
obj.value; // ❌ NOT obj.value()
obj.value = 5; // ✅ Calls setter
b. Class Getter
A getter is a function used to retrieve the value of a property. When you read a property, JavaScript automatically calls the associated getter if one exists.
Syntax
get propertyName() {
// Return the value
return this._propertyName;
}
- Defined with the
getkeyword - Takes no parameters
- Must return a value
Example: Computed Property
class Circle {
constructor(radius) {
this._radius = radius;
}
get area() {
return Math.PI * this._radius ** 2;
}
}
const circle = new Circle(5);
console.log(circle.area); // 78.53981633974483
What’s happening:
areais a computed property — it doesn’t store a value- Every time
circle.areais accessed, the getter runs and computes the area - No parentheses needed — looks like a regular property
Visual:
circle.area
│
▼
get area() {
return Math.PI * this._radius ** 2;
}
│
▼
78.53981633974483
More Getter Examples
class Rectangle {
constructor(width, height) {
this._width = width;
this._height = height;
}
get area() {
return this._width * this._height;
}
get perimeter() {
return 2 * (this._width + this._height);
}
get isSquare() {
return this._width === this._height;
}
get dimensions() {
return `${this._width} × ${this._height}`;
}
}
const rect = new Rectangle(4, 6);
console.log(rect.area); // 24
console.log(rect.perimeter); // 20
console.log(rect.isSquare); // false
console.log(rect.dimensions); // "4 × 6"
Notice: None of these properties are stored — they’re computed on demand.
Getters for Read-Only Properties
Getters (without setters) create read-only properties:
class Person {
constructor(name, birthYear) {
this._name = name;
this._birthYear = birthYear;
}
get name() {
return this._name;
}
get age() {
return new Date().getFullYear() - this._birthYear;
}
// No setter for age — it's computed!
}
const person = new Person('Alice', 1990);
console.log(person.name); // "Alice"
console.log(person.age); // e.g., 34
// person.age = 25; // ❌ Silently fails (or throws in strict mode)
Best Practices for Getters
- ✅ Use getters for accessing properties — whenever you want custom behavior when reading
- ✅ Keep getters simple — focused on returning the property
- ✅ Use for computed properties — when a value derives from other properties
- ❌ Don’t make getters side-effectful — reading a property shouldn’t change state
- ❌ Don’t do heavy computation — getters should be fast
c. Class Setter
A setter is a function used to set or modify the value of a property. When you assign a new value to a property, JavaScript automatically calls the associated setter if one exists.
Syntax
set propertyName(newValue) {
// Modify internal state
this._propertyName = newValue;
}
- Defined with the
setkeyword - Takes exactly one parameter (the new value)
- Should not return a value
Example: Validation with Setter
class Person {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
set name(value) {
if (typeof value === 'string') {
this._name = value;
} else {
console.log('Name must be a string');
}
}
}
const person = new Person('Alice');
person.name = 'Bob';
console.log(person.name); // "Bob"
person.name = 123; // "Name must be a string"
console.log(person.name); // "Bob" (unchanged)
What’s happening:
person.name = 'Bob'triggers the setter- Setter validates the value
- Only valid values update
_name
Visual:
person.name = 123
│
▼
set name(value) {
if (typeof value === 'string') {
this._name = value;
} else {
console.log('Name must be a string'); // ← runs
}
}
More Setter Examples
Age validation:
class User {
constructor(age) {
this.age = age; // Uses setter
}
get age() {
return this._age;
}
set age(value) {
if (!Number.isInteger(value)) {
throw new Error('Age must be an integer');
}
if (value < 0 || value > 150) {
throw new Error('Age must be between 0 and 150');
}
this._age = value;
}
}
const user = new User(25);
console.log(user.age); // 25
user.age = 30;
console.log(user.age); // 30
// user.age = -5; // ❌ Error: Age must be between 0 and 150
// user.age = 3.14; // ❌ Error: Age must be an integer
Email normalization:
class Account {
constructor(email) {
this.email = email; // Uses setter
}
get email() {
return this._email;
}
set email(value) {
if (!value.includes('@')) {
throw new Error('Invalid email');
}
this._email = value.toLowerCase().trim();
}
}
const account = new Account(' Alice@Example.COM ');
console.log(account.email); // "alice@example.com"
Validation Best Practices
| Approach | Example | Use Case |
|---|---|---|
| Throw error | throw new Error('...') | Strict validation — fail fast |
| Silently ignore | return; or log warning | Lenient — don’t break on bad input |
| Clamp value | value = Math.max(0, value) | Constrained numeric values |
| Normalize | value.toLowerCase().trim() | Clean/format input |
Best Practices for Setters
- ✅ Use setters for modifying properties — whenever you want custom behavior when writing
- ✅ Keep setters simple — focused on validation and modification
- ✅ Validate input — reject invalid values
- ✅ Be consistent — if you have a getter, consider having a setter
- ❌ Don’t make setters slow — they run on every assignment
- ❌ Don’t forget to call
this.property = valuein constructor — this triggers the setter
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Class Getters and Setters</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: #f8f9fa;
color: #333;
line-height: 1.6;
}
h1 { color: #007bff; border-bottom: 3px solid #007bff; padding-bottom: 10px; }
h2 { color: #28a745; border-left: 4px solid #28a745; padding-left: 15px; margin-top: 30px; }
.demo-box {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin: 15px 0;
}
pre {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
line-height: 1.8;
}
.keyword { color: #569cd6; }
.string { color: #ce9178; }
.number { color: #b5cea8; }
.function { color: #dcdcaa; }
.comment { color: #6a9955; }
.boolean { color: #569cd6; }
.class-name { color: #4ec9b0; }
.private { color: #c586c0; }
#output {
background: #e9ecef;
padding: 15px;
border-radius: 8px;
margin-top: 15px;
min-height: 40px;
font-family: 'Courier New', monospace;
font-size: 0.85rem;
border-left: 4px solid #007bff;
white-space: pre-wrap;
}
table {
width: 100%;
border-collapse: collapse;
margin: 15px 0;
}
th, td {
padding: 10px;
border: 1px solid #ddd;
text-align: left;
}
th { background: #007bff; color: white; }
tr:nth-child(even) { background: #f8f9fa; }
.btn {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 6px;
font-size: 1em;
font-weight: bold;
cursor: pointer;
margin: 5px;
transition: all 0.3s;
}
.btn:hover {
background: #0056b3;
transform: translateY(-2px);
}
.btn-success { background: #28a745; }
.btn-success:hover { background: #1e7e34; }
.btn-danger { background: #dc3545; }
.btn-danger:hover { background: #a71d2a; }
.class-display {
font-family: 'Courier New', monospace;
font-size: 1.05em;
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
margin: 10px 0;
border-left: 4px solid #007bff;
white-space: pre-wrap;
line-height: 1.8;
}
.input-group {
margin: 10px 0;
}
.input-group label {
display: inline-block;
min-width: 150px;
font-weight: bold;
}
.input-group input {
padding: 8px 12px;
border: 2px solid #ddd;
border-radius: 6px;
font-size: 1em;
width: 200px;
}
.input-group input:focus {
outline: none;
border-color: #007bff;
}
</style>
</head>
<body>
<h1>Class Getters and Setters</h1>
<div class="demo-box">
<h2>1. Validation with Getter and Setter</h2>
<pre>
<span class="keyword">class</span> <span class="class-name">Person</span> {
<span class="function">constructor</span>(name) {
<span class="keyword">this</span>._name = name;
}
<span class="keyword">get</span> <span class="function">name</span>() {
<span class="keyword">return</span> <span class="keyword">this</span>._name;
}
<span class="keyword">set</span> <span class="function">name</span>(value) {
<span class="keyword">if</span> (<span class="keyword">typeof</span> value === <span class="string">'string'</span>) {
<span class="keyword">this</span>._name = value;
} <span class="keyword">else</span> {
console.log(<span class="string">'Name must be a string'</span>);
}
}
}
<span class="keyword">const</span> person = <span class="keyword">new</span> <span class="class-name">Person</span>(<span class="string">'Alice'</span>);
person.name = <span class="string">'Bob'</span>;
console.log(person.name); <span class="comment">// "Bob"</span>
person.name = <span class="number">123</span>; <span class="comment">// "Name must be a string"</span>
</pre>
</div>
<div class="demo-box">
<h2>2. Computed Property with Getter</h2>
<pre>
<span class="keyword">class</span> <span class="class-name">Circle</span> {
<span class="function">constructor</span>(radius) {
<span class="keyword">this</span>._radius = radius;
}
<span class="keyword">get</span> <span class="function">area</span>() {
<span class="keyword">return</span> Math.PI * <span class="keyword">this</span>._radius ** <span class="number">2</span>;
}
}
<span class="keyword">const</span> circle = <span class="keyword">new</span> <span class="class-name">Circle</span>(<span class="number">5</span>);
console.log(circle.area); <span class="comment">// 78.53981633974483</span>
</pre>
</div>
<div class="demo-box">
<h2>3. Getter/Setter Syntax Reference</h2>
<table>
<tr>
<th>Feature</th>
<th>Syntax</th>
<th>Notes</th>
</tr>
<tr>
<td><strong>Getter</strong></td>
<td><code>get name() { }</code></td>
<td>No params, must return</td>
</tr>
<tr>
<td><strong>Setter</strong></td>
<td><code>set name(v) { }</code></td>
<td>One param, no return</td>
</tr>
<tr>
<td><strong>Read (getter)</strong></td>
<td><code>obj.name</code></td>
<td>No parentheses</td>
</tr>
<tr>
<td><strong>Write (setter)</strong></td>
<td><code>obj.name = "x"</code></td>
<td>No parentheses</td>
</tr>
<tr>
<td><strong>Read-only</strong></td>
<td>Getter only</td>
<td>No setter = can't write</td>
</tr>
<tr>
<td><strong>Write-only</strong></td>
<td>Setter only</td>
<td>No getter = can't read</td>
</tr>
</table>
</div>
<div class="demo-box">
<h2>4. Computed Properties Comparison</h2>
<table>
<tr>
<th>Approach</th>
<th>Syntax</th>
<th>Behavior</th>
</tr>
<tr>
<td><strong>Stored property</strong></td>
<td><code>this.x = 5;</code></td>
<td>Value stored in memory</td>
</tr>
<tr>
<td><strong>Computed (getter)</strong></td>
<td><code>get area() { }</code></td>
<td>Computed each access</td>
</tr>
<tr>
<td><strong>Method</strong></td>
<td><code>getArea() { }</code></td>
<td>Must call with <code>()</code></td>
</tr>
</table>
</div>
<div class="demo-box">
<h2>5. Interactive: Person with Validation</h2>
<div class="input-group">
<label for="personName">Name:</label>
<input type="text" id="personName" value="Alice">
</div>
<div style="margin: 10px 0;">
<button class="btn btn-success" onclick="setName()">Set Name</button>
<button class="btn btn-danger" onclick="setInvalidName()">Try Number (invalid)</button>
<button class="btn" onclick="getName()">Get Name</button>
</div>
<div class="class-display" id="personDisplay">Person name: "Alice"</div>
</div>
<div class="demo-box">
<h2>6. Interactive: Circle with Computed Area</h2>
<div class="input-group">
<label for="radiusInput">Radius:</label>
<input type="number" id="radiusInput" value="5" min="0.1" step="0.1">
</div>
<div style="margin: 10px 0;">
<button class="btn btn-success" onclick="updateCircle()">Update Circle</button>
<button class="btn" onclick="showAllComputed()">Show All Properties</button>
</div>
<div class="class-display" id="circleDisplay">Circle with radius 5</div>
</div>
<div class="demo-box">
<h2>7. Live Output — All Examples</h2>
<div id="output">Loading...</div>
</div>
<script>
// ============================================
// Getters and Setters — Live Demo
// ============================================
let results = [];
// 1. Basic getter and setter
results.push('📌 Basic Getter and Setter:\n');
class Person {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
set name(value) {
if (typeof value === 'string') {
this._name = value;
} else {
results.push(' ⚠️ Attempted to set name to ' + value + ' — must be a string');
}
}
}
const person = new Person('Alice');
results.push(' const person = new Person("Alice")');
results.push(' person.name → "' + person.name + '"');
person.name = 'Bob';
results.push(' person.name = "Bob" → person.name = "' + person.name + '"');
person.name = 123; // Triggers validation
results.push(' person.name = 123 → ' + person.name + ' (unchanged)');
results.push('');
// 2. Computed properties
results.push('📌 Computed Properties (Getter):\n');
class Circle {
constructor(radius) {
this._radius = radius;
}
get radius() {
return this._radius;
}
set radius(value) {
if (value <= 0) throw new Error('Radius must be positive');
this._radius = value;
}
get area() {
return Math.PI * this._radius ** 2;
}
get circumference() {
return 2 * Math.PI * this._radius;
}
get diameter() {
return this._radius * 2;
}
}
const circle = new Circle(5);
results.push(' const circle = new Circle(5)');
results.push(' circle.radius → ' + circle.radius);
results.push(' circle.diameter → ' + circle.diameter);
results.push(' circle.area → ' + circle.area.toFixed(4));
results.push(' circle.circumference → ' + circle.circumference.toFixed(4));
results.push('');
circle.radius = 10;
results.push(' After circle.radius = 10:');
results.push(' circle.area → ' + circle.area.toFixed(4) + ' (recomputed!)');
results.push('');
// 3. Read-only property (getter only)
results.push('📌 Read-Only Property (Getter Only):\n');
class Temperature {
constructor(celsius) {
this._celsius = celsius;
}
get celsius() {
return this._celsius;
}
get fahrenheit() {
return this._celsius * 9 / 5 + 32;
}
}
const temp = new Temperature(25);
results.push(' const temp = new Temperature(25)');
results.push(' temp.celsius → ' + temp.celsius);
results.push(' temp.fahrenheit → ' + temp.fahrenheit);
results.push(' → fahrenheit is READ-ONLY (no setter)');
results.push('');
// 4. Full validation
results.push('📌 Full Validation Example:\n');
class User {
constructor(name, age, email) {
this.name = name;
this.age = age;
this.email = email;
}
get name() { return this._name; }
set name(value) {
if (typeof value !== 'string' || value.length < 2) {
throw new Error('Name must be at least 2 characters');
}
this._name = value;
}
get age() { return this._age; }
set age(value) {
if (!Number.isInteger(value) || value < 0 || value > 150) {
throw new Error('Age must be an integer between 0 and 150');
}
this._age = value;
}
get email() { return this._email; }
set email(value) {
if (!value.includes('@')) {
throw new Error('Invalid email');
}
this._email = value.toLowerCase().trim();
}
}
const user = new User('Alice', 30, ' Alice@Example.COM ');
results.push(' const user = new User("Alice", 30, " Alice@Example.COM ")');
results.push(' user.name → "' + user.name + '"');
results.push(' user.age → ' + user.age);
results.push(' user.email → "' + user.email + '" (normalized!)');
results.push('');
try {
user.name = 'A';
} catch (error) {
results.push(' user.name = "A" → ❌ ' + error.message);
}
try {
user.age = -5;
} catch (error) {
results.push(' user.age = -5 → ❌ ' + error.message);
}
try {
user.email = 'invalid';
} catch (error) {
results.push(' user.email = "invalid" → ❌ ' + error.message);
}
results.push('');
// 5. Clamping values
results.push('📌 Clamping Values in Setter:\n');
class Progress {
constructor(value) {
this.value = value;
}
get value() {
return this._value;
}
set value(v) {
// Clamp between 0 and 100
this._value = Math.max(0, Math.min(100, v));
}
}
const progress = new Progress(50);
results.push(' const progress = new Progress(50)');
results.push(' progress.value → ' + progress.value);
progress.value = 150;
results.push(' progress.value = 150 → clamped to ' + progress.value);
progress.value = -10;
results.push(' progress.value = -10 → clamped to ' + progress.value);
results.push('');
// 6. Property with transformation
results.push('📌 Transformation in Setter:\n');
class Slug {
constructor(title) {
this.title = title;
}
get title() {
return this._title;
}
set title(value) {
// Transform to slug
this._title = value
.toLowerCase()
.trim()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '');
}
}
const slug = new Slug(' My First Blog Post! ');
results.push(' const slug = new Slug(" My First Blog Post! ")');
results.push(' slug.title → "' + slug.title + '"');
results.push('');
// 7. Getter-only with setter error
results.push('📌 Getter-Only (Set Attempts Fail):\n');
class Immutable {
constructor() {
this._value = 42;
}
get value() {
return this._value;
}
// No setter
}
const imm = new Immutable();
results.push(' const imm = new Immutable()');
results.push(' imm.value → ' + imm.value);
results.push(' imm.value = 100 → ❌ silently ignored (or TypeError in strict mode)');
results.push(' imm.value → ' + imm.value + ' (unchanged)');
results.push('');
// 8. Practical: Bank account
results.push('📌 Practical: Bank Account:\n');
class BankAccount {
#balance = 0;
constructor(initialBalance) {
this.balance = initialBalance;
}
get balance() {
return this.#balance;
}
set balance(value) {
if (value < 0) throw new Error('Balance cannot be negative');
this.#balance = value;
}
deposit(amount) {
if (amount <= 0) throw new Error('Deposit must be positive');
this.balance = this.#balance + amount;
return this.balance;
}
withdraw(amount) {
if (amount <= 0) throw new Error('Withdrawal must be positive');
if (amount > this.#balance) throw new Error('Insufficient funds');
this.balance = this.#balance - amount;
return this.balance;
}
}
const account = new BankAccount(1000);
results.push(' const account = new BankAccount(1000)');
results.push(' account.balance → $' + account.balance);
results.push(' account.deposit(500) → $' + account.deposit(500));
results.push(' account.withdraw(200) → $' + account.withdraw(200));
try {
account.balance = -100;
} catch (error) {
results.push(' account.balance = -100 → ❌ ' + error.message);
}
results.push('');
// 9. Practical: Config with defaults
results.push('📌 Practical: Config with Defaults:\n');
class Config {
constructor(port, host) {
this.port = port ?? 3000;
this.host = host ?? 'localhost';
}
get url() {
return `http://${this._host}:${this._port}`;
}
get port() { return this._port; }
set port(value) {
if (value < 1 || value > 65535) {
throw new Error('Port must be 1-65535');
}
this._port = value;
}
get host() { return this._host; }
set host(value) {
if (typeof value !== 'string') {
throw new Error('Host must be a string');
}
this._host = value;
}
}
const config = new Config();
results.push(' const config = new Config()');
results.push(' config.url → "' + config.url + '"');
const config2 = new Config(8080, 'example.com');
results.push(' const config2 = new Config(8080, "example.com")');
results.push(' config2.url → "' + config2.url + '"');
results.push('');
// 10. Getter for computed "is" checks
results.push('📌 Practical: Boolean Getter:\n');
class FormField {
constructor(value) {
this._value = value;
}
get value() {
return this._value;
}
set value(v) {
this._value = v;
}
get isEmpty() {
return this._value.trim() === '';
}
get isValid() {
return this._value.length >= 3;
}
get hasSpaces() {
return /\s/.test(this._value);
}
}
const field = new FormField('Hello World');
results.push(' const field = new FormField("Hello World")');
results.push(' field.isEmpty → ' + field.isEmpty);
results.push(' field.isValid → ' + field.isValid);
results.push(' field.hasSpaces → ' + field.hasSpaces);
field.value = 'Hi';
results.push(' After field.value = "Hi":');
results.push(' field.isValid → ' + field.isValid);
document.getElementById('output').textContent = results.join('\n');
// ============================================
// Interactive: Person with Validation
// ============================================
const interactivePerson = new Person('Alice');
function setName() {
const newName = document.getElementById('personName').value;
interactivePerson.name = newName;
document.getElementById('personDisplay').textContent =
`Person name: "${interactivePerson.name}"\n` +
`\n` +
`Setting name to: "${newName}"\n` +
`Result: ✅ Success`;
}
function setInvalidName() {
const oldName = interactivePerson.name;
interactivePerson.name = 12345;
document.getElementById('personDisplay').textContent =
`Person name: "${interactivePerson.name}"\n` +
`\n` +
`Attempted to set name to: 12345 (number)\n` +
`Result: ⚠️ Rejected — name unchanged`;
}
function getName() {
document.getElementById('personDisplay').textContent =
`Person name: "${interactivePerson.name}"\n` +
`\n` +
`Reading via getter: person.name\n` +
`Result: "${interactivePerson.name}"`;
}
// ============================================
// Interactive: Circle
// ============================================
let interactiveCircle = new Circle(5);
function updateCircle() {
const radius = Number(document.getElementById('radiusInput').value);
try {
interactiveCircle.radius = radius;
document.getElementById('circleDisplay').textContent =
`Circle with radius ${interactiveCircle.radius}\n` +
`─────────────────────────────\n` +
`radius: ${interactiveCircle.radius}\n` +
`diameter: ${interactiveCircle.diameter}\n` +
`area: ${interactiveCircle.area.toFixed(4)}\n` +
`circumference: ${interactiveCircle.circumference.toFixed(4)}`;
} catch (error) {
document.getElementById('circleDisplay').textContent =
`❌ Error: ${error.message}`;
}
}
function showAllComputed() {
document.getElementById('circleDisplay').textContent =
`Circle Properties (all computed):\n` +
`─────────────────────────────\n` +
`radius: ${interactiveCircle.radius}\n` +
`diameter: ${interactiveCircle.diameter} (= 2 × radius)\n` +
`area: ${interactiveCircle.area.toFixed(4)} (= π × r²)\n` +
`circumference: ${interactiveCircle.circumference.toFixed(4)} (= 2π × r)\n` +
`\n` +
`→ None of these are stored — computed on demand!`;
}
// Initialize
updateCircle();
</script>
</body>
</html>
Quick Reference
Getter and Setter Syntax
| Feature | Syntax | Rules |
|---|---|---|
| Getter | get name() { } | No params, must return |
| Setter | set name(v) { } | One param, no return |
| Read | obj.name | No parentheses |
| Write | obj.name = value | No parentheses |
Benefits
| Benefit | Description |
|---|---|
| Encapsulation | Hide internal representation |
| Validation | Ensure only valid values are assigned |
| Computed Properties | Define values computed from others |
| Clean Syntax | Access like regular properties |
When to Use Getters
| Scenario | Use Getter? |
|---|---|
| Computed value | ✅ Yes |
| Read-only property | ✅ Yes |
| Formatted output | ✅ Yes |
| Validation on read | ⚠️ Rarely |
| Side effects | ❌ No |
| Heavy computation | ❌ No |
When to Use Setters
| Scenario | Use Setter? |
|---|---|
| Validation | ✅ Yes |
| Normalization | ✅ Yes |
| Clamping values | ✅ Yes |
| Transformation | ✅ Yes |
| Side effects | ⚠️ Cautiously |
| Heavy computation | ❌ No |
Best Practices
✅ Do This:
// Getter for computed values
class Rectangle {
get area() {
return this._width * this._height;
}
}
// Setter for validation
class User {
set age(value) {
if (value < 0) throw new Error('Age cannot be negative');
this._age = value;
}
}
// Use underscore for internal property
class Person {
constructor(name) {
this._name = name; // Internal
}
get name() { return this._name; }
set name(v) { this._name = v; }
}
// Use private fields for true encapsulation
class BankAccount {
#balance = 0;
get balance() { return this.#balance; }
set balance(v) {
if (v < 0) throw new Error('Invalid balance');
this.#balance = v;
}
}
// Call setters in constructor
class Product {
constructor(price) {
this.price = price; // Uses setter for validation
}
set price(value) {
if (value < 0) throw new Error('Price must be positive');
this._price = value;
}
}
❌ Don’t Do This:
// Don't use same name for internal and getter
class Bad {
constructor(name) {
this.name = name; // ❌ Infinite loop!
}
get name() { return this.name; } // Recursion!
}
// Don't forget to return in getter
get name() {
this._name; // ❌ Missing return!
}
// Don't return in setter
set name(value) {
return this._name = value; // ❌ Setters shouldn't return
}
// Don't use getter/setter for performance-critical code
class BadPerf {
get expensiveValue() {
return doHeavyComputation(); // ❌ Runs on every access
}
}
// Don't forget validation in setters
set age(value) {
this._age = value; // ❌ No validation — defeats the purpose!
}
// Don't access #private fields outside class
class BadPrivate {
#value = 42;
}
const obj = new BadPrivate();
// console.log(obj.#value); // ❌ SyntaxError
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| Same name as property | Infinite recursion | Use _ prefix or # |
| Missing return in getter | Returns undefined | Always return |
| Returning in setter | Unexpected behavior | Don’t return |
| Forgetting validation | No benefit from setter | Add validation logic |
Using # outside class | SyntaxError | Only inside class body |
| Heavy computation in getter | Performance issues | Cache or use method |
Getter vs Method
class Rectangle {
constructor(w, h) {
this._w = w;
this._h = h;
}
// Getter — accessed like property
get area() {
return this._w * this._h;
}
// Method — called with parentheses
calculateArea() {
return this._w * this._h;
}
}
const rect = new Rectangle(4, 6);
rect.area; // 24 (getter — no parens)
rect.calculateArea(); // 24 (method — with parens)
rect.area(); // ❌ TypeError: area is not a function
When to use which:
| Use Getter When | Use Method When |
|---|---|
| Value derives from properties | Action/operation |
| No parameters needed | Parameters required |
| Fast computation | Heavy computation |
| Accessed like a property | Clearly an operation |
Pro Tip: Getters and setters are powerful tools for encapsulation and validation. Use them to:
- Compute properties on the fly (
get area()) - Validate input (
set age(value)) - Normalize data (
set email(v) { this._email = v.toLowerCase(); }) - Create read-only properties (getter only)
- Create write-only properties (setter only)
Key rules:
- Getters take no parameters and must return
- Setters take one parameter and should not return
- Use
_prefix for internal properties (convention) - Use
#prefix for truly private fields - Call setters in constructor to ensure validation runs
- Never use the same name for the internal property and the getter — infinite recursion!
Remember: Getters and setters provide a clean API — consumers use obj.prop instead of obj.getProp(). But don’t overuse them! For simple data, plain properties work fine. Use getters/setters when you need validation, computation, or encapsulation.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!