In JavaScript, is it possible to call an instance method on an object that affects all of its siblings?
For example, say I have the following class:
function Thing() {
this.active = false;
}
Thing.prototype = {
constructor: Thing,
activate: function() {
this.active = true;
},
deactivate: function() {
this.active = false;
}
};
Is it possible for me to create an activateAll
method that can activate all of the instances of class Thing
?
I need this.active
to be an instance variable.
You could store all the instances in an array, and iterate them to change their active
property. However, storing all the instances means they won't be garbage collected, so you will waste memory. And if the array becomes huge, iterating it will be slow.
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;
})();
A better way would be defining common default activity and default priority, and an own activity and an own priority for each instance. Then,
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;
})();
If activateAll
will be called lots of times and you don't want to increase defPriority
unnecessarily, you can add a boolean variable to know if some own property reached the default one.
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;
})();
In any case, note that adding that method in the prototype doesn't make much sense. According to the OOP principles, calling a method in a variable should not affect other variables. Instead, consider adding the method to the constructor itself.
A full example could be like this:
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;
})();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With