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