将Object.defineProperty getter还原为原始状态,即常规常量属性

时间:2015-10-17 13:47:03

标签: javascript prototype-programming

我试图以某种方式实现状态效果,以便游戏程序中很少或没有if个案例,也就是说,效果应该适用于对象。

我创建了一个简单的测试用例,这是我计划的基本框架:

// This can represent a game object - player or monster
var test = {damage: 20};
// For the sake of simplicity, I just define
// EffectMissfortune without inheriting other classes
function EffectMissfortune() {

}
/**
 * Applies effect on an object, altering it's properties 
 * until remove is called **/
EffectMissfortune.prototype.apply = function(obj) {
  // Remember oridinal damage
  obj._damage = obj.damage;
  // Define property getter
  Object.defineProperty(obj, "damage", {
    // Has about 40% chance to return 50% damage
    get: function() {
      if(Math.random()<0.4) {
        return this._damage/2; 
      }
      else
        return this._damage;
    },
    // This should allow me to overwrite this, right?
    configurable: true
  });
}
/**
 * Removes anything that was set aby `apply` method**/
EffectMissfortune.prototype.remove = function(obj) {
  obj.damage = obj._damage;
}

我刚刚在Firebug控制台中写过,我省略了很多东西,比如记住应用状态效果等等。重要的是我的.remove方法不起作用:

// Test:
console.log("No effect: ");
console.log(test.damage, test.damage, test.damage, test.damage, test.damage, test.damage, test.damage, test.damage);
// Apply effect
var effect = new EffectMissfortune();
effect.apply(test);
console.log("Missfortune: ");
console.log(test.damage, test.damage, test.damage, test.damage, test.damage, test.damage, test.damage, test.damage);
effect.remove(test);
// Effect removed?
console.log("No effect: ");
console.log(test.damage, test.damage, test.damage, test.damage, test.damage, test.damage, test.damage, test.damage);

输出:

No effect: 
20 20 20 20 20 20 20 20
Missfortune: 
20 10 10 10 10 10 20 10
No effect: 
10 10 20 20 10 20 20 20

所以第一个简单的问题是:

  • 如何删除上次Object.defineProperty来电设置的任何

第二个更难的是:

  • 如果我要一次应用多个效果,我想链接他们定义的任何内容。在这种情况下,我可以在调用自己的Object.defineSettings之前检索当前Object.defineProperty(获取,设置,可配置,可枚举和属性实际值)吗?像Object.getPropertySettings
  • 之类的东西

1 个答案:

答案 0 :(得分:2)

如果您希望能够通过简单的赋值(writable)覆盖属性值,则必须将true属性设置为=configurable属性将允许通过后续调用Object.defineProperty()来更改属性,但不能通过赋值来更改。

编辑 - 但是,属性不能同时为writable 都有访问者方法。在这种情况下,您可以使用另一个.defineProperty()调用删除该值:

EffectMissfortune.prototype.remove = function(obj) {
  Object.defineProperty(obj, "damage", {
    configurable: true,
    writable: true,
    value: obj._damage
  });
}

关于第二个问题,您可以使用Object.keys()获取属性列表,然后对每个属性使用Object.getOwnPropertyDescriptor()