Search code examples
javascriptobjectinitializer

How to use Object Method definitions without entering infinite loop


On MDN there is a sample example showing get and set used on an object initialization:

var o = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {}
};

Without any example showing how to use that structure I always enter in an infinite loop, for example:

var o = {
  property: function (test) {return "test"},
  get property() {return this.property;},
  set property(value) {this.property = value;}
};

When I try to access the object property named property an infinite loop starts, which I assume is because the get also triggers itself when trying to read the property it gets.

console.log(o.property); // infinite loop occurs

So I am assuming that I am doing this wrong, but in that case the example on that web page is not very clear. The temporary solution I found was to save the value in a similar property (_property for example), but I would like to not do this and keep the property name intact for the object, getter and setter.

Is this possible and if so how to do it correctly?


Solution

  • A property of an object can also refer to a function or a getter or setter method.

    A bit confusing but notice the OR. What was meant here is that you can have properties of an object that refer to a function OR you could have properties of an object that refer to getter/setters.

    Getter/setters are simply functions that respect a specific signature and that act as an attribute with additional functionality that can be registered when setting/getting those attributes.

    Typically these are used simply for calculated values, that are based on other state attributes of the object.

    However, in some cases indeed you could use them to add some functionality / pre-calculations when for example setting a value.

    You can do this in many ways, but if you'll still need to have a getter/setter name different than all other attributes on your object.

    So for example having something like this

    var o = {
      prop: 0.6
    }
    

    If you want to add something like having access to a percentage-like value, you can do:

    var o = {
      prop: 0.6,
      get propPerc() { return this.prop * 100; },
      set propPerc(val) { this.prop = this.val / 100; }
    }
    

    But if you want so simply enhance the setting/getting of the prop (for example ensuring you have a numeric value always), you need to do something like:

    var o = {
      _prop: 0.6,
      get prop() { return this._prop || 0; },
      set prop(val) { this._prop = this.val || 0; }
    }
    

    You need a different name for the attribute than the get/set property. For the outside unfortunately both properties will be visible, so if you use this approach it's a matter of convention to not use _prop directly, because JS doesn't have private attributes per se.

    However, you can simulate something like a private attribute using symbols, for example:

    var propSymbol = Symbol('prop');
    
    var o = {
      get prop() { return this[propSymbol] || 0; },
      set prop(val) { this[propSymbol] = this.val || 0; }
    }
    o[propSymbol] = 0.6; // can only do it here, assuming this piece of code is not accessible to outside and propSymbol is just a local variable.
    

    Hope this helps.