I have the following code which defines a Car
. Each Car
has a color, along with a setColor(color)
function. I want to add listener functions which are called whenever setColor(color)
is called, and I want to be able to tack these listener functions on whenever I want. Is this a suitable approach? Is there a cleaner way?
function Car() {
this._color = 'red';
this._callbacks = {};
this.setColor = function(color) {
this._color = color;
console.log(">>> set car color to " + color);
if (this._callbacks['setColor']) {
this._callbacks['setColor']();
}
};
this.addListener = function(functionName, handler) {
if (this._callbacks[functionName]) {
var oldCallback = this._callbacks[functionName];
this._callbacks[functionName] = function() {
oldCallback();
handler();
}
} else {
this._callbacks[functionName] = function() {
handler();
}
}
};
}
var car = new Car();
car.setColor('blue');
car.addListener('setColor', function() { console.log("This is listener # 1"); });
car.setColor('green');
car.addListener('setColor', function() { console.log("This is listener # 2"); });
car.setColor('orange');
Output:
>>> setColor to blue
>>> setColor to green
This is listener # 1
>>> setColor to orange
This is listener # 1
This is listener # 2
I think an array to store the listeners would be a cleaner approach. Also, you should use the prototype object, or make the semiprivate properties real private variables.
function Car() {
this._color = 'red';
this._callbacks = {setColor:[]};
};
Car.prototype.setColor = function(color) {
this._color = color;
console.log(">>> set car color to " + color);
for (var i=0; i<this._callbacks['setColor'].length; i++)
this._callbacks['setColor'][i]();
};
Car.prototype.addListener = function(functionName, handler) {
this._callbacks[functionName].push(handler);
};
Or:
function Car() {
var color = 'red';
var callbacks = {};
this.setColor = function(c) {
color = c;
console.log(">>> set car color to " + color);
for (var i=0; 'setColor' in callbacks && i<callbacks['setColor'].length; i++)
callbacks['setColor'][i]();
};
this.addListener = function(functionName, handler) {
if (functionName in callbacks)
callbacks[functionName].push(handler);
else
callbacks[functionName] = [handler];
};
}
Something like this, perhaps.
//the 'class'
function Car() {
//set up a static listeners object - an array for each method
Car.listeners = {setColor: []};
//called by methods on invocation, to fire their listeners
Car.executeListeners = function(methodName) {
for (var i=0, len = Car.listeners[methodName].length; i<len; i++)
Car.listeners[methodName][i].apply(this);
};
//method - on invocation, fire any listeners
this.setColor = function(color) {
this.color = color;
Car.executeListeners.call(this, 'setColor');
};
}
//instance
var car = new Car();
//add a listener to instance.setColor invocations
Car.listeners.setColor.push(function() {
alert("hello - this car's color is "+this.color);
});
//set color (triggers listener)
car.setColor('orange');
Note you are assigning prototype-esq methods to the instances rather than to the prototype itself - the place for inherited, reusable functionality. Inheritance is also faster in performance terms.
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