简体   繁体   中英

Access default getter/setter for JavaScript object

JavaScript getters and setters can be overridden for specific properties using Object.defineProperty . Is there some way to access the default getter/setter (ie the function used if the getter/setter has not been overwritten)? In my custom setter I want to have special processing in some cases, but use the default processing in others. I tried:

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

Unfortunately this leads to a stack overflow since obj['foo'] = val; causes the custom setter to be invoked. So I'd like to find a way to set the foo property of obj using the default setter. Is this possible?

As far as I know, a property either has a value (data property), or it has getter/setter (accessor property): it cannot have both. Use a local variable under closure, or another property, as an underlying storage for properties where you have a getter/setter defined.

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; }
    });
})();

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

The only way I know how to do that is to make the variable non-private, but two examples, the second more terse:

(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));

So far as I can tell:

  1. You can't reference the value with the same name as what you use in set: function(value) or you end up with an infinite loop where setting the value calls the set value and it calls itself again, and so forth. Hence, your problem.

  2. If you try to make the variable _foo to private, then the setter does not work. With this syntax it seems you can hide the variable, but you cannot really make it private.

You can do something like:

 const counter = new class { count = 1; toString () { return this.count++; } }() console.log(`${counter}`')

 const myString = new class { toString () { return 'This is my string'; } }(); console.log(`${myString}`);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM