1

What is the difference and when would you prefer to use Object.defineProperty vs get/set methods in javascript for getters / setters?

Ex:

class Foo {
    constructor () {
        Object.defineProperty(this, 'bar', {
            get () {
                return this._bar;
            },
            set (value) {
                this._bar = value;
                this.extraFunctionCall();
            }
        })
    }
}

vs

class Foo {
    get bar () {
        return this._bar;
    }

    set bar (value) {
        this._bar = value;
        this.extraFunctionCall();
    }
}
Ashitaka
  • 103
  • 1
  • 5
tam5
  • 165
  • 1
  • 7
  • Possible duplicate of [Are there any OO-principles that are practically applicable for Javascript?](https://softwareengineering.stackexchange.com/questions/180585/are-there-any-oo-principles-that-are-practically-applicable-for-javascript) – gnat Aug 01 '17 at 19:49
  • 5
    `Object.defineProperty` doesn't have to be used within the scope of the class. You can call it at any time on any object. – Samuel Aug 01 '17 at 19:52

4 Answers4

4

They end up being the same. The first is simply a self inflicted monkey patch version of the second.

There really is no reason to do the first this way other than to show off.

That isn't to say that defineProperty() doesn't have proper uses. But this does it in the constructor and with a fixed string. The net result is same behavior and no more flexibility then we have in the second while being less readable.

This reminds me of java's reflection. There is a lot of dangerous power here. Plenty of rope to hang yourself with. Don't mess with this without a good reason.

candied_orange
  • 102,279
  • 24
  • 197
  • 315
3

defineProperty is useful when adding getters/setters for an object that already exists.

However the latter is better for when adding getters/setters to your class, or when you’re creating your Object.

JaseW
  • 31
  • 1
1

The accepted answer is not correct.

Instance vs prototype

By using Object.defineProperty you are defining the property on the instance of the class. When you use a getter/setter, the property is set on the prototype.

This means that in your case, Object.hasOwnProperty will return true with Object.defineProperty and false with the getter/setter.

class Foo {
  constructor () {
    Object.defineProperty(this, 'bar', {
      get () {
        return this._bar;
      },
      set (value) {
        this._bar = value;
        this.extraFunctionCall();
      }
    });
  }

  get baz () {
    return this._baz;
  }

  set baz (value) {
    this._baz = value;
    this.extraFunctionCall();
  }
}

const myFoo = new Foo();
console.log('bar', myFoo.hasOwnProperty('bar'));   // true
console.log('baz', myFoo.hasOwnProperty('baz'));   // false

Object.defineProperty use case

Object.defineProperty is useful when you want to programmatically define more than one property the same way.

For example, I have found it useful when creating Custom Elements because I need to create a lot of properties with the same getter/setter pattern.

class Foo {
  constructor() {
    const defineProperty = property =>
      Object.defineProperty(this, property, {
        get() {
          /* getter definition */
        },
        set(value) {
          /* setter definition */
        },
      });

    defineProperty('bar');
    defineProperty('baz');
  }
}

Here I can define a getter/setter for bar and baz without having to duplicate the code.

As far as I know, there is no way to do this using the getter/setter syntax.

emccorson
  • 11
  • 1
0

The only real usecase for 'defineProperty' in a constructor is, if you want to use the options for 'enumerable' etc.

Bruno Schäpper
  • 1,916
  • 2
  • 14
  • 24