The Object defineProperty() method

By

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:

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: