Currently, everyone is looking forward to JavaScript ES6. However, for many other JavaScript developers and me, ES5 has several interesting built-in methods which are still not commonly known or used. It’s definitely worthwhile to devote some time learning those less popular methods. In my opinion, they are the perfect solution when JavaScript is not only used to modify the DOM elements, but is also responsible for the web application’s logic.
Our task is to create a Person constructor which takes two parameters: firstName and lastName. Our object will expose four attributes: firstName, lastName, fullName and species. The first three will react to changes, and the last one species will have a constant value of 'human'
. Example below:
var woman = new Person('Kate', 'Khowalski');
woman.firstName; // 'Kate'
woman.lastName; // 'Khowalski'
woman.fullName; //'Kate Khowalski
woman.species; // human
/* * Change firstName */
woman.firstName = 'Yulia';
woman.firstName; // 'Yulia'
woman.lastName; // 'Khowalski'
woman.fullName; // 'Yulia Khowalski' - How to do that !?
woman.species = 'fish';
woman.species; // human - No, you can't change this property.
/* * Change fullName */
woman.fullName = 'Joana Stevens';
woman.firstName; //Joana
woman.lastName; //Stevens
Here is the part where Object.defineProperty comes to the rescue. It is a method of ECMAScript 5, and it’s used to define or override the attributes of an object. It accepts as a parameter the object to be modified. The second parameter is the name of the key. The third is the ‘description’ attribute. The ‘description’ field is an object that provides us with the following fields:
A data descriptor also has the following optional keys:
undefined
the getter behavior is ignored. Defaults to undefined.Let’s check now how to solve this task by building the Person
constructor – which for now will have 3 fields: firstName, lastName and species. The fullName field will be implemented later. As we read in the documentation of Object.defineProperty
we can add a field to the object and in descriptor set the writable
attribute to false, which will allow us to protect the value from being overwritten. Let’s see how this works in practice:
var Person = function (first, last) {
this.firstName = first;
this.lastName = last;
}
Object.defineProperty(Person, 'species', {
writable: false,
value: 'human'
});
var woman = new Person('Kate', 'Khowalski');
woman; // Person {firstName: 'Kate', lastName: 'Khowalski', species: 'human'}
/* * Try to overwrite species */
woman.species = 'fish';
woman.species; // 'human' - We can't change this value.
We have now created an attribute which cannot be overwritten. Congratulation on our first success.
Let’s move on to the second part of our task. We need to define a fullName attribute which always will return the current name. Also, we want to be able to set the value of fullName and have the lastName and firstName attributes update accordingly. By using get and set we can define what will happen with the object and what will be returned. Let’s solve this now and see how it works in practice:
var Person = function (first, last) {
this.firstName = first;
this.lastName = last;
};
Object.defineProperty(Person, 'species', {
writable: false,
value: 'human'
});
Object.defineProperty(Person, 'fullName', {
get: function () {
return this.firstName + ' ' + this.lastName;
},
set: function (value) {
var splitString = value.trim().split(' ');
if(splitString.length === 2) {
this.firstName = splitString[0];
this.lastName = splitString[1];
}
}
});
var woman = new Person('Kate', 'Khowalski');
woman.firstName; // 'Kate'
woman.lastName; // 'Khowalski'
woman.fullName; //'Kate Khowalski
woman.species; // human
/* * Change name */
woman.firstName = 'Yulia';
woman.firstName; // 'Yulia'
woman.lastName; // 'Khowalski'
woman.fullName; // 'Yulia Khowalski'
woman.species = 'fish';
woman.species; // human - No, you can't change this properity.
/* * Change fullName */
woman.fullName = 'Joana Stevens';
woman.firstName; //Joana
woman.lastName; //Stevens
Object.defineProperty
is supported by all modern browsers – Internet Explorer 8 supports Object.defineProperty
only for DOM objects. It is worth mentioning that Firefox has performance problems but this is only noticeable when we have more than 100k objects.
This is just one of the many hidden gems of ES5. I encourage you to read the documentation of many other interesting methods like Object.defineProperties()
, Object.freeze()
, Object.keys()
.