The Object defineProperty() method
By Flavio Copes
Learn how the JavaScript Object.defineProperty() method creates or configures a single object property using a property name and a property descriptor object.
Object.defineProperty() creates or configures one property on an object, giving you fine-grained control over how that property behaves. It returns the object.
It takes 3 arguments. The first is the object upon which we’re going to create or configure the property. The second is the property name, as a string. The third is a property descriptor, an object that defines the property.
Example:
const dog = {}
Object.defineProperty(dog, 'breed', {
value: 'Siberian Husky'
})
console.log(dog.breed) //'Siberian Husky'
I didn’t just say breed: 'Siberian Husky' but I had to pass a property descriptor object with a value key.
Why not just assign the property?
Because the descriptor lets you control things a plain assignment can’t. Besides value, it accepts three flags:
writable: can the value be changed?enumerable: does the property show up inObject.keys()andfor...inloops?configurable: can the property be deleted, or its descriptor changed later?
Here’s the catch: with defineProperty(), every flag you don’t specify defaults to false. A property created with a normal assignment has all three set to true.
So the breed property above is locked down more than you might expect:
Object.keys(dog) //[]
dog.breed = 'Labrador'
dog.breed //'Siberian Husky'
delete dog.breed //false
It’s hidden from enumeration, it can’t be reassigned, and it can’t be deleted. If you want a normal-looking property, set the flags explicitly:
Object.defineProperty(dog, 'breed', {
value: 'Siberian Husky',
writable: true,
enumerable: true,
configurable: true
})
Defining getters and setters
Instead of value, a descriptor can define get and set functions. This is how you create a computed property:
const person = {
firstName: 'Flavio',
lastName: 'Copes'
}
Object.defineProperty(person, 'fullName', {
get() {
return `${this.firstName} ${this.lastName}`
}
})
person.fullName //'Flavio Copes'
Notice that a descriptor can have value/writable or get/set, never both. Mixing them throws a TypeError.
A pitfall: silent failures
Writing to a non-writable property doesn’t warn you in non-strict code. The assignment just does nothing, which makes for confusing bugs.
In strict mode (and ES modules are always strict), the same write throws:
TypeError: Cannot assign to read only property 'breed' of object
If a property refuses to update and you don’t know why, inspect it with Object.getOwnPropertyDescriptor(dog, 'breed') and check the writable flag.
Related posts about js: