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

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 propertyconsole.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 modeconsole.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: nameObject.defineProperty(bike, 'name', {writable: false});
// No errorObject.defineProperty(bike, 'name', {configurable: true});
// Throws errordelete 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.