JavaScript — Property Descriptor

In this article, we will learn writable, enumerable and configurable attributes of the property and use of getters and setters.

NC Patro
codeburst

--

learn while relaxing

Property Descriptor

Every object property is more than just a name and value pair. Each property is having property descriptor that helps to see all the attributes of that property.

var bike = {
name: 'SuperSport',
maker: 'Ducati',
engine: '937cc'
};
console.log(Object.getOwnPropertyDescriptor(bike, 'engine'));//Output will be below object
{
configurable: true,
enumerable: true,
value: "937cc",
writable: true
}

In the above code snippet, we are logging all the attributes of property engine of object bike using method getOwnPropertyDescriptor(). So, we can see that addition to the value attribute, it has three more attributes (configurable, enumerable and writable). All these are true by default.

Let’s understand all the attributes one by one.

writable attribute

Writable attribute decides whether the value associated with the property can be changed or not, from its initial value. we can modify the property attributes using method Object.defineProperty() like below

var bike = {
name: 'SuperSport',
maker:'Ducati',
engine:'937cc'
};
Object.defineProperty(bike, 'engine', {writable: false});bike.engine = '2000cc';
// Throws error in strict mode
// Uncaught TypeError: Cannot assign to read only property
console.log(bike.engine);
// Output will be 937cc in non-strict mode

In the above code snippet, we can see that writable attribute of property engine modified to false means we made it non-writable. Then if we try to change the value of engine property, it throws error saying “TypeError: Cannot assign to read only property”. But error shows only if the code is executed in strict mode otherwise it silently fails and value of engine property does not get updated. So bike.engine still prints its original value in case of non-strict mode.

Let’s go through one more example to understand the interesting part of writable property. If the non-writable property itself is an object then we can modify the property of that object. In the below code snippet, property engine is now an object and assigning new value to bike.engine.cc is allowed. It means only modifying the engine property itself is not allowed but properties of engine can be changed.

'use strict';
var bike = {
name: 'SuperSport',
maker:'Ducati',
engine:{cc: '937', type: 'petrol'}
};
Object.defineProperty(bike, 'engine', {writable: false});bike.engine.cc = '950';
console.log(bike.engine);
//Output will be
{
cc: "950",
type: "petrol"
}

If we still want to make the object to be non-writable completely along with its properties then we can use the method Object.freeze() as shown below

var bike = {
name: 'SuperSport',
maker:'Ducati',
engine:{cc: '937', type: 'petrol'}
};
Object.defineProperty(bike, 'engine', {writable: false});
Object.freeze(bike.engine);
bike.engine.cc = '950';
// Throws error in strict mode
console.log(bike.engine.cc);
// Output will be 937 in non-strict mode

Object.defineProperty() is capable of adding new property on an object as well along with modifying an existing property.

enumerable attribute

By default, properties of any object are enumerable means we can loop over them. But the default behavior can be modified by setting enumerable attribute to false for that property as shown below

var bike = {
name: 'SuperSport',
maker:'Ducati',
engine: {cc: '937', type: 'petrol'}
};
Object.defineProperty(bike, 'maker', {enumerable: false});for(let propName in bike) {
console.log(propName);
}
// Output: name engine (property maker is missing)
var keys = Object.keys(bike);
console.log(keys);
// Output: ["name", "engine"] (property maker is missing)

In the above code snippet, Object.keys() method returns an array of a given object’s own enumerable properties but it only enumerates name and engine property and skipped the maker property because enumerable attribute of property maker is set to false.

for..in loop helps to traverse through entire object.

configurable attribute

We can configure all the attributes of the object. But if we set configurable attribute to false, it prevents certain attributes being changed and prevents the deletion of the property itself.

var bike = {
name: 'SuperSport',
maker: 'Ducati',
engine: '937cc'
};
Object.defineProperty(bike, 'name', {configurable: false});Object.defineProperty(bike, 'name', {enumerable: false});
// TypeError: Cannot redefine property: name
Object.defineProperty(bike, 'name', {writable: false});
// No error
Object.defineProperty(bike, 'name', {configurable: true});
// Throws error
delete bike.name;
// TypeError: Cannot delete property 'name' (strict mode only)

As per the above code snippet, we can see that once configurable attribute is set to false .It does not allow to modify the enumerable and configurable attribute but it does allow to change writable attribute and we can not delete the property as well if configurable attribute is set to false. (we need to remove the first error statement to see the later errors in console because execution stops once it hits first error in the code)

All attributes can be modified in a single statement of Object.defineProperty() as well like below without any error.

var bike = {
name: 'SuperSport',
maker: 'Ducati',
engine: '937cc'
};
Object.defineProperty(bike, 'name', {
configurable: false,
writable: false,
enumerable: false,
value: '1000cc'
});

get and set attributes

Attributes get and set are functions which works as getter and setter respectively for the property. When the property is accessed, get function gets called without any arguments and when the property is assigned with some value then set function gets called with the value assigned to the property. To create getter and setter, we need to use method Object.defineProperty() as specified below

var fuel = 'petrol';
var car = {
name: 'SuperFast',
maker: 'Ferrari',
engine: 'v12'
};
Object.defineProperty(car, 'engineDetails', {
get: function() {
return fuel +" "+ this.engine + " engine";
},
set: function(details) {
let splits = details.split(' ');
fuel = splits[0];
this.engine = splits[1];
}
});
console.log(car.engineDetails); // output: petrol v12 enginecar.engineDetails = "diesel v8";
console.log(car.engineDetails); // output: diesel v8 engine

In the above code snippet, engineDetails is a new property to the object car which is having get and set attributes defined. We can still able to access the property like any other property even though behind the scene it actually executes the function get and set. So, we can see that getter and setter are very powerful because we can do lot more things apart from normal retrieve and assignment operation.

In the above code, the keyword this is execution context object . To understand how keyword this works in details, you can go through my article JavaScript — All about this and new keyword .

Summary

We learned all about the JavaScript Object Property Attributes. Starting with property descriptor. Next, we learned use of writable, enumerable and configurable attribute. Finally understood the power of get and set attribute.

If you like this post and it was helpful, please click the clap 👏 button multiple times to show support, thank you.

--

--

Developer | Mentor | Public Speaker | Technical Blogger | Love for Photography and Programming | twitter: @ncpatro