javascriptpropertiesoverridinggetter-setterdefineproperty

How to "override" a defined (get-)property on a prototype?


I have some code which defines a getter (but no setter, if such is relevant) on a prototype. The value returned is correct in 99.99% of the cases; however, the goal is to set the property to evaluate to a different value for a specific object.

foo = {}
Object.defineProperty(foo, "bar", {
    // only returns odd die sides
    get: function () { return (Math.random() * 6) | 1; }
});

x = Object.create(foo);
x.bar       // => eg. 5
x.bar = 4   // by fair dice roll
x.bar       // nope => eg. 3

How can the property be overridden for x, an existing object, such that it is assignable (eg. has default property behavior)?

Addendum: While a new property (value or get/set) can defined on x, I am looking for if there is a way to stop the behavior of a property in the [prototype] and turn "bar" back into a normal/ad-hoc property for the specific instance.


Solution

  • By using Object.defineProperty on x:

    var foo = {}
    Object.defineProperty(foo, "bar", {
        // only returns odd die sides
        get: function () { return (Math.random() * 6) | 1; }
    });
    
    var x = Object.create(foo);
    display(x.bar);      // E.g. 5
    
    (function() {
      var bar;
      var proto = Object.getPrototypeOf(x); // Or just use foo
    
      Object.defineProperty(x, "bar", {
        get: function () { return typeof bar !== "undefined" ? bar : proto.bar; },
        set: function(value) { bar = value; }
      });
    })();
    
    display(x.bar);  // Still odd
    x.bar = 4;       // By fair dice roll
    display(x.bar);  // Shows 4
    
    function display(msg) {
      document.body.insertAdjacentHTML("beforeend", "<p>" + msg + "</p>");
    }

    I am looking for if there is a way to stop the behavior of a property in the [prototype] and turn "bar" back into a normal/ad-hoc property.

    Okay, that's slightly different, but still uses Object.defineProperty:

    var foo = {}
    Object.defineProperty(foo, "bar", {
        // only returns odd die sides
        get: function () { return (Math.random() * 6) | 1; }
    });
    
    var x = Object.create(foo);
    display(x.bar);      // E.g. 5
    
    Object.defineProperty(x, "bar", {
      value: undefined,
      writable: true,
      enumerable: true // Or leave off if you want it non-enumerable
    });
    
    display(x.bar);  // undefined
    x.bar = 4;       // By fair dice roll
    display(x.bar);  // Shows 4
    
    function display(msg) {
      document.body.insertAdjacentHTML("beforeend", "<p>" + msg + "</p>");
    }