Javascript Tutorial
Javascript Tutorial Introduction to Javascript JavaScript Code Editors & IDE JavaScript Hello World Example Javascript Syntax and Rules syntax_rules javascript_identifiers JavaScript Keywords & Reserved Words javascript_variables JavaScript Const JavaScript let vs var vs const Data Types in JavaScript JavaScript String Template Literals & String interpolation in JavaScript Tagged Templates in JavaScript String to Number in JavaScript Number Data Type in JavaScript NaN in JavaScript JavaScript Number Min & Max & Safe Values JavaScript EPSILON & Floating point precision Infinity in JavaScript JavaScript Bigint BigInt Vs Number in JavaScript Boolean Data Type in JavaScript Undefined in JavaScript Null in JavaScript Null vs Undefined in JavaScript JavaScript Operators Arithmetic Operators in JavaScript Unary plus & minus operators in JavaScript Increment & Decrement Operators in JavaScript Comparison or Relational operators in JavaScript Strict Equality (==) Loose Equality (===) in JavaScript Ternary Conditional Operator in JavaScript Logical Operators in JavaScript Bitwise Operators in JavaScript Assignment Operators in JavaScript Nullish Coalescing Operator in JavaScript Comma Operator in JavaScript Typeof JavaScript Operator Precedence in JavaScript JavaScript if, else & nested if statement Switch Statement in JavaScript While & Do While Loops in JavaScript For Loop in JavaScript Break statement in JavaScript Continue Statement in JavaScript Arrays in JavaScript Array Constructor in Javascript Sparse Array Vs Dense Array in JavaScript How to merge Arrays in JavaScript Array Methods in JavaScript Functions in JavaScript Function Parameters & Arguments in JavaScript JavaScript Default Parameters Pass by Value and Pass by Reference in Javascript Function Expression in Javascript Nested Functions in JavaScript Immediately-invoked Function Expressions (IIFE) JavaScript Callback Functions Arrow Functions in JavaScript Arguments Object In JavaScript Rest Parameters in JavaScript Objects in Javascript Create Objects in JavaScript JavaScript Object Properties Computed Property Names in JavaScript Object Literal in JavaScript Constructor Function & New Operator in JavaScript Delete Operator in JavaScript hasOwnProperty in JavaScript Using Getters and Setters in Javascript DefineProperty in JavaScript JavaScript Property Descriptors Enumerable, Writable & Configurable Object Destructuring in JavaScript Variable Scope in JavaScript Hoisting in JavaScript Lexical Scope & Closures in JavaScript This in JavaScript Global Object, Window & Globalthis in JavaScript Call function in Javascript Prototype In Javascript Prototype Inheritance in JavaScript Instanceof Operator in JavaScript Spread Operator in JavaScript

Using Getters and Setters in JavaScript

The Getters and Setters in JavaScript are known as accessor properties. They look like normal properties but are actually functions mapped to a Property. We use “get” to define a getter method and “set” to define a setter method. The Setter method runs when we assign a value to the Property. The Getter method runs when we access the Property.

What are Getters & Setters in JavaScript

The Getters and setters are known as Accessor Properties in JavaScript.

We learned about JavaScript Properties. Property is a variable attached to the JavaScript object. We can assign value to the Property or retrieve its value at any time.

Properties are classified based on how we assign value to them or retrieve value from them. There are two kinds of properties in JavaScript. They are

  1. Data Properties
  2. Accessor Properties.

The Data Property is mapped to a value. The value can be a primitive value, object, or function. In the following example, firstName, lastName & age are data properties. We assign or retrieve the values from these properties directly.

        
var person = { 
    firstName:"",     
    lastName:"",      
    age: 0            
};
 
person.firstName="Allie"           // => Assign a value
console.log(person.firstName)   //Allie         => Retrieve a value  
 
 
                
        
    

The accessor property is not mapped to a value but to a function. We call this function as accessor function. It is the job of the accessor function to store or retrieve the value.

The accessor function that retrieves the value of a property is known as the Getter method. We use the Get keyword to declare a Getter method.

The accessor function that assigns a value to a property is known as the Setter method. We use the Set keyword to declare a Setter method.

The Getter and Setter methods are useful when we do not want to access the property directly.

How to Create Getters & Setters

There are two ways to create Getter & Setter properties in JavaScript.

  1. Object Literal
  2. DefineProperties Method

There is an older syntax, __defineGetter__ and __defineSetter__, but it’s deprecated

Using Object Literal

The following is the syntax for creating a Getter & Setter property using the object Literal syntax or object initializer.

JavaScript Getter

We use the get keyword followed by a function expression. The name of the function becomes the name of the property ( propName in the above example).

The following is the syntax of the getter method.

        
let obj = {
  get propName() {
    // getter method
    // this code is executed when we access the property using 
    // Example value = obj.propName
  },
} 
 
 
                
        
    

The getter function executes when we read the value of the Property. Note that we cannot pass an argument to the getter method. The return value of the getter method becomes the value of the property access expression.

In the following example, color is a getter property, while _color is a regular Property. The color function returns the value of the _color property.

        

var car = { 
 
  _color: "blue", 
 
  // Accessor Property with the name color
  get color() {                    //getter
      return this._color; 
  }, 
 
};
 
console.log(car.color)
 
                
        
    

We access the color getter property just like any other Javascript Property. i.e. using the dot notation

        
console.log(car.color)
 
                
        
    

Note that although the color is a function, we do not invoke it like a function i.e car.color(). But access it just like a property i.e. car.color

Javascript Setter

To create a setter method, we use the set keyword followed by a function expression. The name of the function becomes the name of the property ( propName in the above example).

The following is the syntax of the setter method.

        
let obj = {
 
  set propName(value) {
    // setter method
    // the code is executed when we assign a value to the property 
    // Example obj.propName = value
  }
};
 
 
                
        
    

The setter method executes when we assign a value to the property. JavaScript invokes the setter method with the value of the right-hand side of the assignment as the argument. If the setter method returns a value then it is ignored.

In the following example, color is a setter property, while _color is a regular Property. The color function accepts a value and updates the _color property.

        
var car = { 
  _color: "blue", 
  
  set color(value) {               //setter
      this._color=value; 
  }    
};
 
car.color="red";
 
 
                
        
    

We assign a new value to the color setter property just like any other Javascript Property. i.e. using the assignment.

In the code car.color="red"; the assignment value (i.e. red in the example) is passed as the argument to the setter method. Not that we do not invoke the setter property as car.color("red") but as car.color="red".

Javascript Getter & Setter

The combined syntax for creating both setter and getter is as shown below.

        
let obj = {
  get propName() {
    // getter method
    // this code is executed when we access the property using 
    // Example value = obj.propName
  },
 
  set propName(value) {
    // setter method
    // the code is executed when we assign a value to the property 
    // Example obj.propName = value
  }
};
 
                
        
    

The example code using both getter & Setter is as follows

        
var car = { 
 
  //Regular Property 
  //Also known as backing Property to color getter & setter property
  _color: "blue", 
  
  // Accessor Property with the name color
  get color() {                    //getter
      return this._color; 
  }, 
  set color(value) {               //setter
      this._color=value; 
  }    
};
 
//Using the getter method
console.log(car.color);  //blue  
 
 
//Setting color. Runs the setter method
car.color="red";
console.log(car.color);  //red  Accessing the property
 
//You can also access the backing property
console.log(car._color);  //red
 
                
        
    

When we access the car.color the getter method executes and it returns the value of the _color property.

We assign the car.color="red" the setter method executes. Inside the setter method, we assign the value to the property _color.

Notice that the color accessor property behind the scene uses the _color property to store the value. _color property is the backing property of the color accessor property. As a convention, we prepend the backing property with an underscore to indicate that _color should not be accessed directly.

Note that you cannot use the same name for an accessor property and a regular property.

Since ES6, you can also use the computed property names in getters & setters also. Simply enclose the expression inside square brackets( []).

        
colorVar="color"
 
var car = { 
 
  _color: "blue", 
  
  get [colorVar]() {                   
      return this._color; 
  }, 
  set [colorVar](value) {              
      this._color=value; 
  }    
};
 
console.log(car.color);  //blue  
 
car.color="red";
console.log(car.color);  //red  
 
                
        
    

Using DefineProperties

We can add a getter & setter on existing objects using the defineProperty function.

TThe definePropery not only allows us to add a new property but also allows us to set its descriptors ( known as accessor descriptors) or flags. The accessor descriptors have the following properties.

get is a function without arguments that serves as a getter for the property.

set is a function with one argument that serves as a setter for the property.

enumerable if true, then this property shows up during the enumeration of the properties. Defaults to false.

configurable if true, then we are allowed to modify the property descriptor and delete the property. Defaults to false.

        
var car = { 
  _color: "blue", 
};
 
 
Object.defineProperty(car, 'color', {     
     get: function() { return this._color },     
     set: function(value) { this._color = value },
     enumerable: true,
     configurable: true,
}) 
 
console.log(car.color);  
 
car.color="red";
console.log(car.color);  
 
console.log(car._color);   
 
                
        
    

Using Getters & Setters

Use getter or setter only when you need a specific functionality provided by them.

There is no need to use accessor methods if you are simply using them to get or set the data property as in the example below. Plain property access is a better option here.

        
const person = {
  _name: "",
  get name() {
    return this._name;    
  },
  set name(value) {
    this._name = value;
  },
};
 
 
                
        
    

But there are some use cases, where you can think of using the Getters & Setters.

Validating values

In the example below, we want to limit the rate field to 10, if the user assigns any rate above 10. This can be easily achieved by a setter method.

        

        var IntCalculator = {
  _rate: 0,
 
  get rate() {
    return this._rate;
  },
  set rate(value) {
    if (value > 10) {
      console.log("Invalid Rate");
      value = 10;
    } else if (value < 0) {
      console.log("Invalid Rate");
      value = 0;
    }
    this._rate = value;
  },
};
 
IntCalculator.rate = 5;
console.log(IntCalculator.rate); //5
 
IntCalculator.rate = 10;
console.log(IntCalculator.rate); //10
 
IntCalculator.rate = 100;
console.log(IntCalculator.rate); //10
 
IntCalculator.rate = -1;
console.log(IntCalculator.rate); //0
 
 
                
        
    

Another use case is to log the values as the property is being read or written.

Read-only /Write-only Properties

We can use the Setters & getters to create read-only or write-only properties.

If the property has only a getter method, then it is a read-only property. If it has only a setter method then it is a write-only property

In the following example, we only define a get method, making the color property read-only. Setting the color property using an assignment ( car.color="red";) will not throw the error, but won’t do anything.

        
var car = { 
 
  _color: "blue", 
  
  get color() {                    
      return this._color; 
  }, 
 
};
 
 
console.log(car.color);  //blue  
 
//Setting color. But it wont work
//as it is read only. No error is thrown
car.color="red";
console.log(car.color);   //blue
 
 
 
                
        
    

Similarly, you can create a write-only property by only defining the setter method. Any attempt to read the write-only property always returns undefined.

        
var car = { 
 
  _color: "blue", 
  
  set color(value) {                    
      this._color=value 
  }, 
 
};
 
//Colod is write only. Hnece always returns undefined
console.log(car.color);  //undefined
 
car.color="red";
console.log(car.color);   //undefined
 
console.log(car._color);  //red
 
 
 
                
        
    

Perform Some logic

In the following IntCalculator, we use the setter method to check if the rate & amount differs from their previous values and calculate the interest if they differ. This helps in saving precious CPU time.

        
var IntCalculator = {
  _amount: 0,
  _rate: 0,
  _int: 0,
 
  get amount() {
    return this._amount;
  },
  set amount(value) {
    if (this._amount != value) {
      this._amount = value;
      this._calcInt();
    }
  },
 
  get rate() {
    return this._rate;
  },
  set rate(value) {
    if (this._rate != value) {
      this._rate = value;
      this._calcInt();
    }
  },
 
  _calcInt() {
    this._int = (this._amount * this._rate) / 100;
    console.log("int calculated")
  },
 
  get int() {
    return this._int;
  },
};
 
 
IntCalculator.amount=1000;
IntCalculator.rate=10;
 
console.log(IntCalculator.int)
 
//Interest is not calculated here
IntCalculator.amount=1000;
 
 
 
                
        
    

We can further optimize the above code, by running the calculation only when the user asks for interest. The code runs the calculations only if the amount & rate differs by checking the _isDirty variable.

        
var IntCalculator = {
  _amount: 0,
  _rate: 0,
  _int: 0,
  _isDirty:true,
 
  get amount() {
    return this._amount;
  },
  set amount(value) {
    if (this._amount != value) {
      this._amount = value;
      this_isDirty=true;
    }
  },
 
  get rate() {
    return this._rate;
  },
  set rate(value) {
    if (this._rate != value) {
      this._rate = value;
      this_isDirty=true;
    }
  },
 
  _calcInt() {
    this._int = (this._amount * this._rate) / 100;
    console.log("int calculated")
  },
 
  get int() {
    if (this._isDirty ) {
      this._calcInt()
      this._isDirty=false
    }
    return this._int;
  },
};
 
 
IntCalculator.amount=1000;
IntCalculator.rate=10;
 
//Interest is now calcuated
console.log(IntCalculator.int)
 
IntCalculator.amount=1000;
 
//Not calculated
console.log(IntCalculator.int)
 
 
 
                
        
    

In the following IntCalculator, we use the setter method to check if the rate & amount differs from their previous values and calculate the interest if they differ. This helps in saving precious CPU time.

Pitfalls

Backing Property

We use the underscore in the property names to indicate that nobody should access these variables.

In the Intcalculator example, if anyone changes the _amount or _rate directly, then our calculator will not calculate the interest correctly and fails. This is because, in JavaScript, you cannot create a private property like in C# or Java.

One simple pattern to avoid such an issue is use the enclose the object in a function and use the concepts of block scope & lexical scope

In the example below, we move the car object inside the function getCar and return it. We move the private property _color outside the car object but inside the function. Due to the rules of block scope, the _color is accessible inside the car object, but not accessible outside the getCar function.

        
            
function getCar() {
  
  let _color= "blue"    //block scoped.out side the object
 
  let car = { 
    get color() {                   
        return _color; 
    }, 
    set color(value) {              
        _color=value; 
    }    
  };
 
  return car
  //returns the object
}
 
car = getCar()  //get the object from the function
 
console.log(car.color);  //blue  
 
car.color="red";
console.log(car.color);  //red  
 
console.log(car._color);  //undefined
 
// This will create a new property in car object   
// But will not affect the color property
car._color="green"  
 
console.log(car.color);   //red  
 
console.log(car._color);  //green.
 
 
 
                
        
    

Getter has higher precedence

You should not give the same name to a getter and a property.

This is because the getter will always take precedence

In the example below, you will never be able to access name property as the getter property name has higher precedence.

        
const person = {
  name: 'Bill Gates',
  get name() {
      return 'Jeff Bezos';
  }
};
 
console.log(person.name)  //Jeff Bezos
 
 
 
                
        
    

If you happen to use the name as the backing property, you will end up with a ” Maximum call stack size exceeded” error as in the example below. this.name inside the getter function resolves to itself hence creating an infinite loop

        
const person = {
  name: 'Bill Gates',
  get name() {
      return this.name;
  }
};
 
 
console.log(person.name)  //Uncaught RangeError: Maximum call stack size exceeded
 
 
 
                
        
    

getValue / setValue pattern

You can implement functionality similar to getter & setter using the getValue / setValue pattern.

                            
var car = { 
 
 _color: "blue", 
 
 getColor() {                   
     return this._color; 
 }, 
 setColor(value) {              
     this._color=value; 
 }    
};

//Getting Color
console.log(car.getColor());  //blue  

//Setting Color
car.setColor("red");
console.log(car.getColor());  //red 

console.log(car._color);  //red
 
  
    
        
    

Read More

  1. JavaScript Tutorial
  2. Objects in JavaScript
  3. Create Objects in JavaScript
  4. Object Properties
  5. Computed Property Names
  6. Object Literal
  7. Constructor functions
  8. DefineProperty
  9. Property Descriptors Enumerable, Writable & Configurable
  10. Object Destructuring