Object.defineProperty只能修改setter吗?

Can Object.defineProperty only modify the setter?

本文关键字:setter 修改 defineProperty Object      更新时间:2023-09-26

我希望我的对象有一个字段,当读取时返回字段的值,当val写入字段时,我想在写入它之前修改val。我现在的代码是这样的:

function Cat(lives) {
    var self = this;
    var privateLives;
    Object.defineProperty(self, 'publicLives', {
        get: function() {return privateLives;},
        set: function(val) {privateLives = 7 * val;}
    });
}

有没有办法做到这一点,而不做一个私有变量?理想情况下,我只需将setter设置为:

function(val) {self.publicLives = 7 * val;}

,但这会导致setter调用自身时溢出。是否有某种方法可以使它不循环setter(因此只有setter作用域外的赋值才能调用setter而setter中的赋值只是进行正常的赋值)?如果可能,当setter写入公共字段时,我也不需要显式地定义getter。

不,这是不可能的-一个属性只能是数据属性或访问器属性,不能两者兼而有之。当然,您不一定需要将值存储在setter的私有变量中,您也可以使用不同的属性或不同对象的属性(如@Oriol的代理)。如果你想避免私有变量,"私有"属性是标准的方法:

function Cat(lives) {
    this.publicLives = lives;
}
Object.defineProperty(Cat.prototype, 'publicLives', {
    get: function() {return this._privateLives;},
    set: function(val) { this._privateLives = 7 * val;}
});

但是你也可以做一些棘手的事情,通过使用一个反复重新定义的常量getter函数来隐藏"私有变量":

Object.defineProperty(Cat.prototype, 'publicLives', {
    set: function setter(val) {
        val *= 7;
        Object.defineProperty(this, 'publicLives', {
            get: function() { return val; }
            set: setter,
            configurable: true
        });
    }
});

在ES6中,另一种选择是使用带有[[Set]] trap的Proxy对象:

function Cat(lives) {
  return new Proxy(this, {
    set: function(target, prop, val) {
      target[prop] = val;
      if (prop === 'publicLives') target[prop] *= 7;
      return true;
    }
  });
}