通过实例方法修改类的所有成员



在JavaScript中,是否有可能在影响其所有兄弟姐妹的对象上调用实例方法?

例如,假设我有以下类:

function Thing() {
  this.active = false;
}
Thing.prototype = {
  constructor: Thing,
  activate: function() {
    this.active = true;
  },
  deactivate: function() {
    this.active = false;
  }
  
};

我是否可以创建一个可以激活Thing类的所有实例的activateAll方法?

我需要this.active是一个实例变量。

您可以将所有实例存储在一个数组中,并迭代它们以更改它们的active属性。但是,存储所有实例意味着它们不会被垃圾收集,因此您将浪费内存。如果数组变得很大,迭代它会很慢。

var Thing = (function() { // Use a closure to hide `instances`
  var instances = [];
  function Thing() {
    this.active = false;
    instances.push(this);
  }
  Thing.prototype.activate = function() {
    this.active = true;
  };
  Thing.prototype.activateAll = function() {
    instances.forEach(function(instance) {
      instance.active = true;
    });
  };
  return Thing;
})();

一个更好的方法是定义公共默认活动和默认优先级,并为每个实例定义自己的活动和优先级。然后,
  • 要获得实例的活动,比较默认优先级和自身优先级。最大的决定是返回默认活动还是返回自己的活动。
  • 要设置实例的活动,请更新自己的活动。
  • 如果默认活动值更大,则增加自己的优先级。
  • 设置所有实例的活动,更新默认活动并增加默认优先级。
var Thing = (function() {
    var defActive = false, /* default activity */
        defPriority = 0; /* default priority */
    /* `defPriority >= ownPriority` will always hold */
    function Thing() {
        var ownActive,
            ownPriority = -1;
        Object.defineProperty(this, 'active', {
            get: function() {
                return defPriority > ownPriority ? defActive : ownActive;
            },
            set: function(val) {
                ownActive = val;
                ownPriority = defPriority;
            }
        });
    }
    Thing.prototype.activate = function() {
        this.active = true;
    };
    Thing.prototype.activateAll = function() {
        defActive = true;
        ++defPriority;
    };
    return Thing;
})();

如果activateAll将被调用很多次,并且你不想不必要地增加defPriority,你可以添加一个布尔变量来知道某些自己的属性是否达到默认值。

var Thing = (function() {
  var defActive = false, /* default activity */
      defPriority = 0, /* default priority */
      someOwnPriorityReachedDefPriority = false;
  function Thing() {
    var ownActive,
        ownPriority = -1;
    Object.defineProperty(this, 'active', {
      get: function() {
        return defPriority > ownPriority ? defActive : ownActive;
      },
      set: function(val) {
        ownActive = val;
        ownPriority = defPriority;
        someOwnPriorityReachedDefPriority = true;
      }
    });
  }
  Thing.prototype.activate = function() {
    this.active = true;
  };
  Thing.prototype.activateAll = function() {
    defActive = true;
    if(someOwnPriorityReachedDefPriority) {
      ++defPriority;
      someOwnPriorityReachedDefPriority = false;
    }
  };
  return Thing;
})();

在任何情况下,请注意在原型中添加该方法没有多大意义。根据面向对象原则,调用变量中的方法不应该影响其他变量。相反,可以考虑将该方法添加到构造函数本身。

一个完整的例子可能是这样的:

var Thing = (function() {
  var defActive = false, /* default activity */
      defPriority = 0, /* default priority */
      someOwnPriorityReachedDefPriority = false;
  function Thing() {
    var ownActive,
        ownPriority = -1;
    Object.defineProperty(this, 'active', {
      get: function() {
        return defPriority > ownPriority ? defActive : ownActive;
      },
      set: function(val) {
        ownActive = val;
        ownPriority = defPriority;
        someOwnPriorityReachedDefPriority = true;
      }
    });
  }
  Thing.prototype.activate = function() {
    this.active = true;
  };
  Thing.prototype.deactivate = function() {
    this.active = false;
  };
  Object.defineProperty(Thing, 'activeAll', {
    set: function(val) {
      defActive = val;
      if(someOwnPriorityReachedDefPriority) {
        ++defPriority;
        someOwnPriorityReachedDefPriority = false;
      }
    }
  });
  Thing.activateAll = function() {
    Thing.activeAll = true;
  };
  Thing.deactivateAll = function() {
    Thing.activeAll = false;
  };
  return Thing;
})();

您需要一个instances数组,像这样:

var instances = [];

修改Thing如下:

function Thing() {
  this.active = false;
  instances[instances.length] = this;
}

通过迭代实现方法:

function activateAll() {
    for (var index in instances) {
        instances[index].active = true;
    }
}

你可以概括如下:

function genericOperation(f, p) {
    for (var index in instances) {
        instances[index].f(p);
    }
}

最新更新