Default getter / setter access for JavaScript object

JavaScript getters and setters can be overridden for specific properties using Object.defineProperty

. Is there a way to access the default getter / setter (i.e. a function to use if the getter / setter hasn't been overwritten)? In my custom setter, I want to have special handling in some cases, but use the default handling in others. I tried:

Object.defineProperty(obj, 'foo',
  'set': function(val) {
    if (useCustom) {
      doCustomProcessing(obj, 'foo', val);
    }
    else {
      obj['foo'] = val;
    }
  }
);

      

Unfortunately this results in a stack overflow because it obj['foo'] = val;

invokes a custom installer call. So I would like to find a way to set the property foo

obj

using the default setter. Is it possible?

+3


source to share


4 answers


As far as I know, a property either has a value (data property) or has a getter / setter property (accessor property): it cannot have both. Use a local variable on close or another property as the underlying storage for properties that define the getter / setter qualifier.

For example,



(function() {
    var value;
    Object.defineProperty(obj, 'foo', {
      set: function(val) {
        if (useCustom) {
          value = doCustomProcessing(obj, 'foo', val);
        } else {
          value = val;
        }
      },
      get: function() { return value; }
    });
})();

      

+3


source


In ES6, you can use a proxy object :



var myObject = {};

var myProxyObject = new Proxy(myObject, {
  set: function(ob, prop, value) {
    if (prop === 'counter' && value === 10) {
      // Some specialised behaviour
      ob.counter = 0;
    }
    else {
      // Default setter behaviour.
      ob[prop] = value;
    }
    // Return true otherwise you will get a TypeError in strict mode.
    return true;
  }
});

>>> myProxyObject.counter = 5;
>>> console.log(myProxyObject.counter);
5

>>> myProxyObject.counter = 10;
>>> console.log(myProxyObject.counter);
0

      

+2


source


The only way I know how to do this is to make the variable non-unique, but with two examples, the second is more concise:

(function testInheritance(global, doc) {
  "use strict";
  var MyFunc = Object.create({}, {
      _foo: {
        value: "Some Default Value",
        writable: true,
        enumerable: true
      },
      foo: {
        get: function() {
          return this._foo;
        },
        set: function(value) {
          this._foo = value;
        }
      }
    }),
    testFunc = Object.create(MyFunc);
  console.log(testFunc.foo); // "Some default value"
  testFunc.foo = "boo";
  console.log(testFunc.foo); // "boo";
 testFunc._foo = "Not a private variable anymore";
 console.log(testFunc.foo); // "Not a private variable anymore"
}(window, document));

(function testInheritanceTwo(global, doc) {
  "use strict";
  var MyFunc = Object.create({}, {
      foo: {
        get: function() {
          if (!this._foo) {
             return "Some default value set by the getter.";
          }
          return this._foo;
        },
        set: function(value) {
          this._foo = value;
        }
      }
    }),
    testFunc = Object.create(MyFunc);
  console.log(testFunc.foo); // "Some default value set by the getter."
  testFunc.foo = "Whomp";
  console.log(testFunc.foo); // "Whomp";
 testFunc._foo = "Not a private variable anymore, unfortunately.";
 console.log(testFunc.foo); // "Not a private variable anymore"
}(window, document));

      

As far as I can tell:

  • You cannot reference a value with the same name as you use in set: function (value), or you end up in an infinite loop in which setting a value calls the given value and calls it again, and so on. Hence your problem.

  • If you try to make _foo private, then the setter is not working. With this syntax, it seems like you can hide the variable, but you cannot make it private.

+1


source


I think you are trying to find an inheritance mechanism for getters and setters ...

var useCustom;
var obj1 = {
   set foo(val){
     console.log(val + " : foo : obj1");
   }
};

var obj2 = {
   set foo(val){
     if (useCustom) {
      console.log(val + " : foo : obj2");
    }
    else {
      Object.getPrototypeOf(obj2).foo = val;
    }
   }
};

Object.setPrototypeOf(obj2,obj1);

useCustom = true;
obj2.foo = "test1";  //test1 : foo : obj2
useCustom = false;
obj2.foo = "test2";  // test2 : foo : obj1

      

0


source







All Articles