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.
Want me to talk about your product? You can sponsor this site.
Related posts about js: