1 Introduction.
By default, Object properties created using assignment operator are mutable and enumrable using loop, it means that they can be updated or deleted from the Object.
Object.defineProperty
allows us to pricisely define or modify existing property on an object and change those extra details of a property from their defaults. we will see exactly what are those extra details and how to change their default values later in this article.
Method Syntax-
Object.defineProperty(objectName, propertyName, descriptor)
Here
objectName
is an object on which to define the property.propertyName
is the name of the property, it could be anything.descriptor
the descriptor object for the property.
Let's take an quick look how adding properties to an object using assignment (=
) operator and Object.defineProperty
looks like -
let obj = {}
obj.property = "Some value"
writable
,configurable
andenumerable
will betrue
if property is added using assignment operator.
For example, The above code snippet is equivalent to this Object.defineProperty
method call.
let obj = {}
Object.defineProperty(obj, "property", {
value: "Some value",
writable: true,
configurable: true,
enumerable: true,
})
2. descriptor
object keys
descriptor
object has a few attributes to define the behaviour of a property, we will see how each attribute can be used to define the behaviour of object property.
2.a value
The value associated with the property, can be any JavaScript value eg. number, boolean, function etc. By default its value is undefined
.
2.b writable
writable
attribute is used to define whether the property value can be updated with an =
(assignment) operator or not. By default its value is false
.
Let's see how to add a read-only property to an JavaScript Object -
let batman = {}
//lets add an favourite color property
Object.defineProperty(batman, "favouriteColor", {
value: "Black",
writable: false, //value can't be updated
enumerable: true, //iterable using loops
})
Here we added a favouriteColor
property to batman
object, favouriteColor
property value is "Black" and it can't be re-assigned or updated because descriptor.writable
is false
.
Let's try to update batman.favouriteColor
from Black to Green.
batman.favouriteColor ='Green'; //throws error in strict mode
console.log(batman.favouriteColor); //still prints 'Black'
In above code snippets, Trying to update a non-writable property operation failed and it didn't throw any error (unless you are using strict mode).
2.c configurable
configurable
attribute is used to define whether the property descriptor can be updated and property can be deleted from the object or not. By default its value is false
.
setting configurable
to false
means that -
- the property can not be deleted from the object
- its descriptor object can not be modified using
Object.defineProperty
.
Basically once you set configurable
to false
, the property (not its value) is freezed on the object, you can not set configurable
to back to true
for that property.
keep in mind that property value can be updated as long as writable
is set to true
. setting configurable
to false
does not prevent property value being updated.
We already made sure that batman.favouriteColor
value is not changable by setting writable
attribute to false, now let's make sure that no one can remove favouriteColor
property from batman
object by setting configurable
to false
.
Object.defineProperty(batman, "favouriteColor", {
value: "Black",
writable: false, //value can't be updated
configurable: false,
enumerable: true, //iterable using loops
})
If property already exist on the object, Object.defineProperty
will update the existing property (only if configurable
is set to true
);
Now, Trying to delete the favouriteColor
property from the batman
object using delete
operator will return false.
delete batman.favouriteColor //returns false
console.log(batman) // { favouriteColor: 'Black' }
Once configurable
is set to false
, you can't -
- Delete the key from the object , trying to do so will not throw an error
- Set
configurable
totrue
for that property, trying to do so will throw an error - Change
enumerable
property value
However, as i've already mentioned that property value can be updated (using .
or []
notation ) as long as writable
is set to true
. setting configurable
to false
does not prevent property value being updated.
2.d enumerable
:
enumerable
attribute controls whether the property will show up or not during enumeration of the properties using for..in
loops.
Sometimes you don't want certain properties to show up while iterating over the object keys. Let's add an speak
method to batman
object -
function speak() {
console.log("I'm Batmannn")
}
//let's add it to the batman object
batman.speak = speak
console.log(batman) //{ favouriteColor: 'Black', speak: [Function: speak] }
Let's try to loop over the batman
object -
for (let prop in batman) {
console.log(prop)
}
//favouriteColor
//speak
But what if we don't want speak
to be accessible using loop? well you can use enumerable
property to hide speak
property from loops. By default enumerable
value is false
.
Let's hide speak
property from for..in
loop.
Object.defineProperty(batman, "speak", {
value: speak,
writable: true,
configurable: true,
enumerable: false, //hidden from loop
})
Now speak
property won't show while iterating over batman
object -
for (let prop in batman) {
console.log(prop)
}
//favouriteColor
Property that has enumerable
set to false
-
- will not show in
for..in
loop. - will not be serialized using
JSON.stringify
. - will not show up in an array returned by
Object.keys(batman)
. - will not be picked up by
Object.assign()
or spread operator. - are accessible using
.
or[]
notation.
You can check whether a property is enumerable or not by using propertyIsEnumerable function, it returns true if property is enumerable.
Conclusion
By default Object properties are mutable, but sometimes you may want to change their default behaviour to achieve the objective. In that case it's good to have an idea about Object.defineProperty
method and how it works.
Highly recommend to visit these links because there is a lot more to know about Object.defineProperty
-