JavaScript getters and setters are special methods that let you control how an object’s properties are read and updated. A getter runs when you access a property, while a setter runs when you assign a value to it. They make it possible to calculate values, validate input, and keep an object’s data consistent while using familiar property syntax.

JavaScript Getter Syntax

You define a getter inside an object literal by writing the get keyword followed by the property name and a function body. The getter does not take parameters and returns the value that should be provided when the property is accessed.

const person = {
  firstName: "Nadia",
  lastName: "Islam",

  get fullName() {
    return this.firstName + " " + this.lastName;
  }
};

console.log(person.fullName); // "Nadia Islam"

In this example, fullName is a getter. When JavaScript evaluates person.fullName, it runs the getter and returns the combined name. Notice that the property is accessed without parentheses: person.fullName, not person.fullName().

JavaScript Setter Syntax

A setter uses the set keyword and accepts one parameter. That parameter receives the value assigned to the property. You can then store the value or perform validation before updating the object’s internal data.

const person = {
  _age: 0,

  set age(value) {
    if (value < 0) {
      console.log("Age cannot be negative.");
      return;
    }

    this._age = value;
  }
};

person.age = 25;

console.log(person._age); // 25

person.age = -5; // "Age cannot be negative."

When the statement person.age = 25 runs, JavaScript calls the age setter and passes 25 as its argument. The setter checks the value before storing it in _age. The underscore is a naming convention often used for an internal backing property; it does not make the property truly private.

Using Getters and Setters Together

You can define a getter and setter with the same property name. This is useful when you want to validate stored data and also expose a calculated or formatted value through a simple property.

const user = {
  _name: "",

  get name() {
    return this._name;
  },

  set name(value) {
    if (typeof value !== "string" || value.trim() === "") {
      console.log("Please enter a valid name.");
      return;
    }

    this._name = value.trim();
  }
};

user.name = "  Rahim  ";

console.log(user.name); // "Rahim"

user.name = ""; // "Please enter a valid name."

The setter validates and trims the input before saving it. The getter returns the stored value. From the outside, the code still uses normal property assignment and property access, even though custom logic runs behind the scenes.

Getters and Setters in JavaScript Classes

JavaScript classes also support getters and setters. They are declared inside the class body using the same get and set keywords. This is a common way to validate or calculate values for class instances.

class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  get area() {
    return this.width * this.height;
  }

  set dimensions(value) {
    if (
      !value ||
      typeof value.width !== "number" ||
      typeof value.height !== "number" ||
      value.width <= 0 ||
      value.height <= 0
    ) {
      throw new Error("Width and height must be positive numbers.");
    }

    this.width = value.width;
    this.height = value.height;
  }
}

const rectangle = new Rectangle(10, 5);

console.log(rectangle.area); // 50

rectangle.dimensions = { width: 8, height: 4 };

console.log(rectangle.area); // 32

The area getter calculates the area from the current width and height, so the value stays up to date when the dimensions change. The dimensions setter validates both values before updating the instance.

Using Getters with Computed Property Names

Getter and setter names can also be computed using square brackets. This is helpful when a property name is stored in a variable or needs to be generated dynamically.

const propertyName = "fullName";

const person = {
  firstName: "Ava",
  lastName: "Morgan",

  get [propertyName]() {
    return this.firstName + " " + this.lastName;
  }
};

console.log(person.fullName); // "Ava Morgan"

Here, JavaScript evaluates propertyName when creating the object and uses its value, "fullName", as the getter’s property name. Learn more about this related feature in our guide to JavaScript Computed Properties.

Creating Getters and Setters with Object.defineProperty()

You can define an accessor property after an object has been created by using Object.defineProperty(). Its descriptor accepts get and set functions, as well as options such as enumerable and configurable.

const product = {
  _price: 100
};

Object.defineProperty(product, "price", {
  get() {
    return this._price;
  },

  set(value) {
    if (typeof value !== "number" || value < 0) {
      throw new Error("Price must be a non-negative number.");
    }

    this._price = value;
  },

  enumerable: true,
  configurable: true
});

product.price = 150;

console.log(product.price); // 150

In this example, Object.defineProperty() creates the price accessor. Setting enumerable: true makes it appear in operations such as Object.keys(). Setting configurable: true allows the property descriptor to be changed or the property to be deleted, subject to the usual property rules.

Important Rules for Getters and Setters

1. A getter takes no parameters. Its job is to return a value when the property is read.

2. A setter accepts one parameter. That parameter receives the value being assigned to the property.

3. Accessors are used like properties. Read a getter with object.property and invoke a setter with object.property = value. Do not call them with parentheses.

4. Avoid recursive accessors. A getter or setter should not read from or assign to the same accessor property inside its own body. Doing so can cause an endless call and a stack overflow. Use a separate backing property instead.

const account = {
  _balance: 0,

  get balance() {
    return this._balance; // Read the backing property
  },

  set balance(value) {
    this._balance = value; // Update the backing property
  }
};

account.balance = 500;
console.log(account.balance); // 500

5. Keep getters predictable. A getter is usually best when it returns a value without unexpectedly changing the object’s state or performing expensive work. Since it looks like a property read, surprising side effects can make code harder to understand.

Categorized in:

Javascript, JS Basic,