In the Previous Tutorial, we learned the following –
- Adding Object properties to an existing Object
- When to use bracket notation to access object property?
- Adding methods to an existing Object
- Removing Object properties from an Object
- Getting the list of object properties
- Filtering the properties using typeof operator
In this tutorial, we’ll learn about a popular stuff in programming world – getters and setters. In JavaScript, getters and setters are defines differently that most of the programming languages.
Why the heck do I need to know this new thing. If I can access an object property I can easily get and set its value.
Genuine question! Let me try to answer it by revising our famous car object.
Let us say, in the same car you also want to have a topSpeed property but you want anyone can update its value. Obviously, you do not want anyone who has access to the car to play with its mechanics and change the top speed. It may cause accident.
Hey, I’ve read This Tutorial and I know I can hide any property from the end user. Why don’t we use it?
We’ll still use that learning and create a local variable inside the Constructor Function. But we still need a way so that users of the car can know the topSpeed. Obviously, they cannot set it.
In other words we want to have have a read-only property. We can define a getter for this topSpeed local variable.
How to declare Getter in JavaScript?
We can use Object.defineProperty() method to define a property and use get keyword to set getter to that property. Object.defineProperty() takes three arguments – First argument is the object for which you want to define the property. The argument is the property name and the third argument is an object literal.
We know from This Tutorial that we can refer the current object by using this keyword inside a Constructor Function.
This is how we can use Object.defineProperty() inside a Constructor Function –
function Car(make, model) {
this.make = make;
this.model = model;
var maxSpeed = 200;
Object.defineProperty(this, 'topSpeed', {
get: function(){
return maxSpeed;
}
});
}
var car = new Car('Toyota', 'Corolla');
Did you Notice?
We did not declare the maxSpeed using this keyword like make or model properties. Because we know from This tutorial that doing so would have exposed maxSpeed to the users of this car. Also we used get keyword to define a function that should be called whenever that property topSpeed is accessed. This function just returns the local variable maxSpeed.
Lets Experiment
Save the code. If the Live Server is running go to the browser console and run this command – car.topSpeed
You should get the top speed of the car i.e. 200.
Let’s now try to access the local variable maxSpeed by using this command – car.maxSpeed. You should get undefined.
Lets do some more Experiment
Go the browser console and check if the topSpeed is indeed a read-only property. Can you update it?
If you try to set the topSpeed you do not get any error. But you must have noticed every time you try to access the getter you get the same value. It means the value is never updated.
As we know from This Tutorial that Objects in JavaScript are dynamic, we can either define properties while declaring the Constructor Function
How to declare Setter in JavaScript?
Suppose we want to have one more property gear and declare both its getter and setter.
Wait… What is the incentive of defining setter for the gear? I can directly update its value.
Well, do you want the users of the car to set -100 as the value of the gear. Does it make sense?
If you want to put some validation logic before setting a value, it makes sense to declare a setter.
This is how we can declare a setter for gear with some validations –
var gear;
Object.defineProperty(this, 'gear', {
get function(){
return gear;
},
set: function(value){
if(value < 0 || value > 5){
throw new Error('Gear must be between 1 and 5');
}
gear = value;
}
});
Updated myjs.js
function Car(make, model) {
this.make = make;
this.model = model;
var topSpeed = 200;
Object.defineProperty(this, 'topSpeed', {
get: function(){
return topSpeed;
}
});
var gear;
Object.defineProperty(this, 'gear', {
get function(){
return gear;
},
set: function(value){
if(value < 0 || value > 5){
throw new Error('Gear must be between 1 and 5');
}
gear = value;
}
});
}
var car = new Car('Toyota', 'Corolla');
Lets Experiment
Try setting an invalid value for the gear. It must throw an error.
Do you Know?
As objects in JavaScript are dynamic, you can also define getters-setters after creating the object.
Let us add a new property brand and a getter for it after creating a car.
Updated myjs.js
function Car(make, model) {
this.make = make;
this.model = model;
var topSpeed = 200;
Object.defineProperty(this, 'topSpeed', {
get: function(){
return topSpeed;
}
});
}
var car = new Car('Toyota', 'Corolla');
Object.defineProperty(car, 'brand', {
get: function(){
return car.make + ' ' + car.model;
}
});
Did you Notice?
We have not passed this as the first argument while using defineProperty() for brand. Instead, we have used object car. But for topSpeed we have passed this keyword.
This is because we have used defineProperty() for topSpeed inside the Constructor Function. And we know from This Tutorial that we can use this keyword to refer to the object that invoked that function.
But we have used defineProperty() for brand outside the Constructor Function. And we know that the first argument of defineProperty() is the object on which we want to define the property. So it is car.
We learned a lots of stuffs about objects in this and the previous tutorials. We explored how to implement two of the four OOP principles – Encapsulation and Inheritance.
In the next couple of tutorials, we’ll learn how to implement another Object-oriented principle – Inheritance. And knowing prototypes is the first step in that direction. Let’s explore it in the Tutorial.