JavaScript对象的默认getter/setter访问方法

7

使用Object.defineProperty,可以覆盖特定属性的JavaScript getter和setter。有没有一种方法可以访问默认getter/setter(即如果getter/setter未被覆盖,则使用的函数)?在我的自定义setter中,我想在某些情况下进行特殊处理,但在其他情况下使用默认处理。我尝试过:

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

不幸的是,这会导致堆栈溢出,因为 obj [ 'foo'] = val; 会导致调用自定义setter。所以我想找到一种使用默认setter设置 obj 的 foo 属性的方法。这可行吗?

4个回答

8
据我所知,属性要么有值(数据属性),要么有getter/setter(访问器属性):它们不能同时存在。在具有getter/setter定义的属性中,可以使用闭包下的本地变量或另一个属性作为底层存储。
例如,
(function() {
    var value;
    Object.defineProperty(obj, 'foo', {
      set: function(val) {
        if (useCustom) {
          value = doCustomProcessing(obj, 'foo', val);
        } else {
          value = val;
        }
      },
      get: function() { return value; }
    });
})();

1
@OP,要了解数据属性和访问器属性的更多信息,请参见ECMAScript 5,第8.6节 - apsillers

7
在ES6中,您可以使用代理对象
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

1
唯一我知道的方法是将变量设为非私有,下面是两个例子,第二个更简洁:
(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));

据我所知:
  1. 如果你在set函数中使用与值相同的名称来引用该值,那么你会遇到无限循环的问题,因为设置该值会调用set值,然后再次调用自身,如此往复。这就是你的问题所在。

  2. 如果您尝试将变量_foo设为私有,则setter不起作用。使用这种语法似乎可以隐藏变量,但实际上无法使其成为私有变量。


0
你可以这样做:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接