Let's say I have Player object:
var player = function(name) {
this.handlers = {};
}
player.prototype.on = function(event, callback) {
if (!this.handlers[event]) {
this.handlers[event] = [];
}
this.handlers[event].push(callback);
}
It works great, I can create players and each will have its own set of handlers. Now suppose I need to inherit from player
:
var testPlayer = function(name) {
this.name = name;
};
testPlayer.prototype = new player();
Now when I create testPlayer
's, each of them share the same handlers
property:
var adam = new testPlayer('Adam');
adam.on('test', function(){});
var eve = new testPlayer('Eve');
// eve.handlers == {'test':<function>}
What am I missing here? I understand than every testPlayer
's prototype is the same new player
object I create when describing child class. But is there some way for all testPlayers to have their own set of handlers?
The problem here is that handlers
is a property that was added in the constructor, so when you do
testPlayer.prototype = new player();
you're adding every property of a brand new player
object to testPlayer.prototype
, and that includes handlers
.
So, there's a handlers
property in every testPlayer
object, and when you add a property to handlers
you're adding the property to the object in the prototype, and not of the testPlayer
object.
In short, when calling the on
method you're adding a property to testPlayer.prototype.handlers
, not adam.handlers
or eve.handlers
.
To be safe, define:
var testPlayer = function(name) {
this.name = name;
this.handlers = {};
};
That sure looks strange for those used to classical inheritance, but it's how prototypal inheritance works. To have a separate handlers object per instance, you need to specify one on the child constructor. That will shadow the prototype's property with the same name:
var testPlayer = function(name) {
this.name = name;
this.handlers = {};
};
testPlayer.prototype = new player();
Another solution would be to create this shadowing property on-demand, from your on
method:
player.prototype.on = function(event, callback) {
// Check for a handlers property on the instance
if(!this.hasOwnProperty('handlers') {
this.handlers = {};
}
if (!this.handlers[event]) {
this.handlers[event] = [];
}
this.handlers[event].push(callback);
}
Interesting fact
This is only a problem if you're modifying properties of an object (or array) on the prototype. If you try to assign to properties that live on the prototype, a local shadowing property will be created automatically (you can't assign to prototype properties from instances).
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