liveBook · Manning

Object.defineProperty

As explained in Secrets of the JavaScript Ninja, Second Edition

A JavaScript method that defines or modifies a property on an object with explicit control over its attributes.

Ordinary assignment is convenient, but it gives you little say over how a property behaves. Object.defineProperty lets you define a property on an object using a descriptor: pass the object, the property name, and the descriptor. It is handy when a property should remain accessible without appearing in a for-in loop—or when reading and writing it should run code. section 7.3.1 section 8.1.1

Choose the behavior you need:

  • Use value for the stored value, writable to permit assignment, enumerable to include the property in for-in enumeration, and configurable to control reconfiguration. section 7.3.1
  • Use get and set functions to respond to property reads and writes. They cannot be combined with value and writable in the same descriptor. section 7.3.1 section 8.1.1

Accessible, but out of the loop

`Object.defineProperty(ninja, "sneaky", { configurable: false, enumerable: false, value: true, writable: true })` creates an accessible property that a for-in loop does not visit. By contrast, properties added with ordinary assignment are enumerable, configurable, and writable. section 7.3.1

A practical prototype fix uses the same tool. Replacing a constructor’s prototype with an instance of another constructor establishes inheritance but loses the original prototype’s constructor property. Define `constructor` on the replacement prototype with the intended function as its value and `enumerable: false`; instances can then report the intended constructor without adding it to for-in results. section 7.3 section 7.3.1

Listing 8.4. Defining getters and setters with Object.defineProperty
  function Ninja() {                                  #A
    let _skillLevel = 0;                              #B

    Object.defineProperty(this, 'skillLevel', {       #C
      get: () => {                                    #D
        report("The get method is called");           #D
        return _skillLevel;                           #D
      },                                              #D
      set: value => {                                 #E
        report("The set method is called");           #E
        _skillLevel = value;                          #E
      }                                               #E
    }); 
  }

  const ninja = new Ninja();                          #F

  assert(typeof ninja._skillLevel === "undefined",             #G
         "We cannot access a 'private' property");             #G
  assert(ninja.skillLevel === 0, "The getter works fine!");    #G

  ninja.skillLevel = 10;                                       #H
  assert(ninja.skillLevel === 10, "The value was updated");    #H

A getter and setter defined on `skillLevel` log property access while reading and updating a variable held inside the constructor. section 8.1.1

If property reads and writes need hooks, an accessor descriptor can make ordinary-looking property access run getter and setter functions. The same functions can also be declared in an object literal or an ES6 class; use Object.defineProperty when you need to define the property through a descriptor. section 8.1.1

How Secrets of the JavaScript Ninja, Second Edition covers it

How deep it goes
Works through descriptor attributes, a constructor-property repair, and a getter/setter implementation rather than merely naming the API.
Examples
Uses a nonenumerable `sneaky` property, a restored prototype `constructor`, and a `skillLevel` property backed by getter and setter functions.
What it assumes
Builds on object-property assignment and constructor prototypes while introducing descriptor configuration explicitly.
What you can do after
Apply it via Object.defineProperty to control enumeration, restore a prototype’s constructor property, or define getter and setter behavior.
How it connects
Connects property descriptors to for-in enumeration, prototype inheritance, constructor properties, getters, setters, and closures.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Secrets of the JavaScript Ninja, Second Edition. The section links point to the parts of the book it draws on.