Skip to main content

JavaScript Getters and Setters

Introduction

In JavaScript, objects are collections of key-value pairs where values can be accessed directly through their corresponding keys. However, sometimes we need more control over how properties are accessed or modified. This is where getters and setters come into play.

Getters and setters are special methods that allow you to define how object properties are accessed (get) and modified (set). They enable you to:

  • Execute code when properties are read or written
  • Validate data before assigning it to a property
  • Compute values on-the-fly
  • Implement data encapsulation and hide internal implementation details

Let's dive into how they work and why they're useful for JavaScript developers.

Understanding Getters

A getter is a method that gets the value of a specific property. When you access the property, the getter function is called, and the return value of the function becomes the value of the property.

Basic Getter Syntax

There are two ways to define getters in JavaScript:

1. Using the get keyword in an object literal:

javascript
const person = {
firstName: "John",
lastName: "Doe",

// Getter
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
};

console.log(person.fullName); // Output: John Doe

Notice that when accessing person.fullName, we don't use parentheses like a normal function call. The getter is accessed as if it were a regular property.

2. Using Object.defineProperty():

javascript
const person = {
firstName: "John",
lastName: "Doe"
};

Object.defineProperty(person, 'fullName', {
get: function() {
return `${this.firstName} ${this.lastName}`;
}
});

console.log(person.fullName); // Output: John Doe

Understanding Setters

A setter is a method that sets the value of a specific property. When you assign a value to the property, the setter function is called with the new value as an argument.

Basic Setter Syntax

Similar to getters, there are two ways to define setters:

1. Using the set keyword in an object literal:

javascript
const person = {
firstName: "John",
lastName: "Doe",

set fullName(name) {
const parts = name.split(' ');
this.firstName = parts[0];
this.lastName = parts[1] || '';
}
};

person.fullName = "Jane Smith";
console.log(person.firstName); // Output: Jane
console.log(person.lastName); // Output: Smith

2. Using Object.defineProperty():

javascript
const person = {
firstName: "John",
lastName: "Doe"
};

Object.defineProperty(person, 'fullName', {
set: function(name) {
const parts = name.split(' ');
this.firstName = parts[0];
this.lastName = parts[1] || '';
}
});

person.fullName = "Jane Smith";
console.log(person.firstName); // Output: Jane
console.log(person.lastName); // Output: Smith

Combining Getters and Setters

Getters and setters are often used together to create a "pseudo-property" that behaves like a regular property but has custom access control:

javascript
const circle = {
_radius: 5, // Convention: underscore indicates private property

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 * this._radius;
}
};

console.log(circle.radius); // Output: 5
console.log(circle.area); // Output: 78.53981633974483

circle.radius = 10;
console.log(circle.area); // Output: 314.1592653589793

// This would throw an error:
// circle.radius = -5;

In this example:

  • _radius is the actual stored property (with the underscore convention indicating it's "private")
  • radius is a getter/setter pair that controls access to _radius
  • area is a read-only computed property (only has a getter)

Practical Applications of Getters and Setters

1. Data Validation

Setters are excellent for validating data before assigning it:

javascript
const user = {
_email: '',

get email() {
return this._email;
},

set email(value) {
// Simple email validation
if (!/^\S+@\S+\.\S+$/.test(value)) {
throw new Error('Invalid email format');
}
this._email = value;
}
};

user.email = "[email protected]"; // Valid
console.log(user.email); // Output: [email protected]

// This would throw an error:
// user.email = "invalid-email";

2. Computed Properties

Getters can calculate values on-demand:

javascript
const product = {
name: 'Laptop',
price: 999,
discount: 0.1,

get discountedPrice() {
return this.price * (1 - this.discount);
}
};

console.log(product.discountedPrice); // Output: 899.1

3. Unit Conversion

Getters and setters can handle unit conversions automatically:

javascript
const temperature = {
_celsius: 0,

get celsius() {
return this._celsius;
},

set celsius(value) {
this._celsius = value;
},

get fahrenheit() {
return (this._celsius * 9/5) + 32;
},

set fahrenheit(value) {
this._celsius = (value - 32) * 5/9;
}
};

temperature.celsius = 25;
console.log(temperature.fahrenheit); // Output: 77

temperature.fahrenheit = 68;
console.log(temperature.celsius); // Output: 20

4. In Classes

Getters and setters are commonly used in JavaScript classes:

javascript
class Person {
constructor(firstName, lastName, age) {
this._firstName = firstName;
this._lastName = lastName;
this._age = age;
}

get firstName() {
return this._firstName;
}

set firstName(value) {
if (typeof value !== 'string') {
throw new Error('First name must be a string');
}
this._firstName = value;
}

get lastName() {
return this._lastName;
}

set lastName(value) {
if (typeof value !== 'string') {
throw new Error('Last name must be a string');
}
this._lastName = value;
}

get fullName() {
return `${this._firstName} ${this._lastName}`;
}

get age() {
return this._age;
}

set age(value) {
if (value < 0 || value > 120) {
throw new Error('Age must be between 0 and 120');
}
this._age = value;
}
}

const john = new Person('John', 'Doe', 30);
console.log(john.fullName); // Output: John Doe

john.firstName = 'Jane';
console.log(john.fullName); // Output: Jane Doe

// This would throw an error:
// john.age = 150;

Best Practices for Getters and Setters

  1. Keep them simple: Getters and setters should be fast and not have side effects that users wouldn't expect

  2. Use the underscore convention for "private" backing properties (e.g., _propertyName)

  3. Always include validation in setters when appropriate

  4. Consider providing both getter and setter for a property, unless you want it to be read-only

  5. Avoid circular references in getters that might cause infinite loops

  6. Don't perform expensive operations in getters if they'll be called frequently

When to Use Getters and Setters

  • When you need to validate data before assignment
  • When a property requires computation
  • When property access needs to trigger side effects
  • When implementing data encapsulation
  • When you need backward compatibility after refactoring

Summary

Getters and setters are powerful JavaScript features that provide control over property access in objects. They allow you to:

  • Execute code when properties are accessed or modified
  • Validate property values
  • Create computed properties
  • Transform data during assignment or retrieval
  • Implement proper encapsulation

By using getters and setters appropriately, you can create more robust and maintainable JavaScript objects with controlled access to their data.

Exercises

  1. Create an object representing a bank account with properties for balance and owner. Add getters and setters that prevent the balance from going negative.

  2. Create a Rectangle class with width and height properties. Add getters and setters for both properties that ensure they are positive numbers. Add a getter for area that computes the area on-the-fly.

  3. Create an object that stores temperatures in Celsius but has getters and setters for Celsius, Fahrenheit, and Kelvin.

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)