ES5 / 6类中多个相同的getter / setter函数的良好解决方案?

时间:2017-11-09 11:33:44

标签: javascript class getter-setter

我正在寻找一种优雅的方法来为ES6类中的多个属性声明相同的getter / setter。

而不是有一大堆:

  set prop_1(value){
      this.prop_1 = value;
      console.log(`set prop_1 = ${value} and calling updateroom`);
      db.updateRoom(this, 'prop_1');
  }

...

  set prop_n(value){
      this.prop_n = value;
      console.log(`set prop1 = ${value} and calling updateroom`);
      db.updateRoom(this, 'prop_n');
  }

我想在与其他getter和setter相邻的类定义中做一些像这样可维护的东西:

['prop_1', 'prop_2' ... 'prop_n'].forEach(prop => {
      set [prop](value) {
        this[prop] = value;
        console.log(`set ${prop} = ${value} and calling updateroom`);
        db.updateRoom(this, prop);
      }
});

但当然不能在类定义中做到这一点,因为文字不是句法允许的东西之一。

稍后通过例如:

声明后,甚至无法将setter添加到类定义中
class Room {
// stuff
}

['initialised', 'type', 'owner'].forEach(prop => {
    Object.defineProperty(Room, prop, {
      set: function(value) {
        this[prop] = value;
        console.log(`set ${prop} = ${value} and calling updateroom`)
        db.updateRoom(this, prop);
      }
})

因为那时没有实例。

所以最终走下了一条装饰构造函数的神秘路径,这意味着任何人都试图找出我之后想要实现的目标,最终导致半小时的头痛和更复杂的事情。

我错过了什么,有没有人想出一种优雅的编码方式,而不重复吸气装置?

1 个答案:

答案 0 :(得分:2)

  

我想在与其他getter和setter相邻的类定义中做一些像这样可维护的东西:

['prop_1', 'prop_2' ... 'prop_n'].forEach(prop => {
      set [prop](value) {
        this[prop] = value;
        console.log(`set ${prop} = ${value} and calling updateroom`);
        db.updateRoom(this, prop);
      }
});

  

在稍后通过例如:......声明后,甚至无法将setter添加到类定义中,因为此时没有实例。

是的,但可以使用Object.defineProperty来执行此操作,在对象上设置属性,这些属性将成为这些实例的原型(Room.prototype)。在class声明之后:

class Room {
    // ...
}

...您可以将这些设置者添加到Room.prototype

['prop_1', 'prop_2'/* ... 'prop_n'*/].forEach(prop => {
    Object.defineProperty(Room.prototype, prop, {
        set: function(value) {
            // ...save the value somewhere (*NOT* `this[prop] = value;`,
            // which will call the setter again, resulting in a stack
            // overflow error...
        }
    });
});

请记住,class符号主要是关于原型继承的语法糖(但是,你知道,好的种糖)。你仍然有一个Room.prototype对象,在class声明之外向它添加内容是完全有效的。

实例(在本例中,我只是将值存储在单独的values属性对象上)

class Room {
    constructor() {
       this.values = {};
    }
}
['prop_1', 'prop_2', 'prop_n'].forEach(prop => {
    Object.defineProperty(Room.prototype, prop, {
        set: function(value) {
            console.log(`set ${prop} = ${value}...`);
            this.values[prop] = value;
        },
        get: function() {
            return this.values[prop];
        }
    });
});

const r = new Room();
r.prop_1 = 42;
console.log("r.prop_1 = ", r.prop_1);
r.prop_2 = "Answer";
console.log("r.prop_2 = ", r.prop_2);