Reputation: 108
I'm trying to create a 'class like' inheritance system in JS using functions and prototypes. The idea is to achieve something similar to ExtJS class system without the overhead of the entire framework.
So by now I created an ObjectBase
function, modified its prototype to contain some shared functionalities
and wrote an injectProto()
function to merge two functions prototypes (in a loop).
Here's the injectProto()
code
/**
* Injects a function's prototype into another function's prototype.
*
* @param {Function} fn1 The function to inject into
* @param {Function} fn2 The function to inject from
* @return {Function} The injected function
*/
function injectProto(fn1, fn2) {
for (var m in fn2.prototype) {
Object.defineProperty(fn1.prototype, m, {
value: fn2.prototype[m]
});
}
fn1.prototype.constructor = fn1;
fn1.prototype.parent = fn2.prototype;
return fn1;
}
And the ObjectBase
code
/**
* Base Object, provides shared functionalities.
*
* [!] All functions extend this one
*
*/
var ObjectBase = function(){
};
var ObjectBase.prototype = {
constructor: ObjectBase,
parent: none,
listeners: [],
addListener: function(listener) {
this.listeners.push(listener);
},
getListeners: function() {
return this.listeners;
},
removeListener: function(listener) {
for (var i = 0; i < this.listeners.length; i++) {
if (listener === this.listeners[i]) {
this.listeners.splice(i, 1);
break;
}
}
}
};
Now, the problem.
If I create a 'subclass' using injectProto
and make new instances of it, they all share the same reference to the
listeners
property.
So if I add a listener to a subclass instance (foo) every other instance (bar) gets a new listener.
// 1. Inject ObjectBase proto into an empty function
var Foo = injectProto(function(){}, ObjectBase);
// 2. Make some instances
var foo = new Foo();
var bar = new Foo();
// 3. Add a dummy listener to foo
foo.addListener( function(){ console.log("I'm Batman!") } );
// 4. Appreciate my confusion
console.log( foo.getListeners() );
console.log( bar.getListeners() );
Output:
[function()]
[function()] // Should be empty (?)
Why is that? I did assign every single property from one prototype to the other inside injectProto
. Could anyone help me here?
Thanks
Upvotes: 1
Views: 74
Reputation: 36592
To answer your questions, you have the property listeners
set on the prototype, so it is shared by all instances. Your constructor needs to create this property on each instance object instead.
function ObjectBase() {
this.listeners = [];
this.parent = 'none'; // you have `parent: none` which will error as `none` is undefined
}
As an aside, don't use delete
to remove elements from an array; you'll muck up the indexes. Use a proper array method like splice
. Also, don't use for..in
on arrays.
Upvotes: 1