我正在尝试使用函数和原型在JS中创建一个'类似'的继承系统。 我们的想法是在没有整个框架的开销的情况下实现类似于ExtJS类系统的东西。
所以到现在为止我创建了一个ObjectBase
函数,修改了它的原型以包含一些共享功能
并编写了一个injectProto()
函数来合并两个函数原型(在一个循环中)。
这是injectProto()
代码
/**
* 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;
}
ObjectBase
代码
/**
* 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;
}
}
}
};
现在,问题。
如果我使用injectProto
创建'子类'并创建它的新实例,它们都共享相同的引用
listeners
财产。
因此,如果我向子类实例(foo)添加一个侦听器,则每个其他实例(bar)都会获得一个新的侦听器。
// 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() );
输出:
[function()]
[function()] // Should be empty (?)
为什么?我确实将每个属性从一个原型分配到injectProto
内的另一个属性。有人可以帮我吗?
由于
答案 0 :(得分:1)
要回答您的问题,您在原型上设置了属性listeners
,因此所有实例都会共享该属性。您的构造函数需要在每个实例对象上创建此属性。
function ObjectBase() {
this.listeners = [];
this.parent = 'none'; // you have `parent: none` which will error as `none` is undefined
}
顺便说一句,不要使用delete
从数组中删除元素;你会搞砸索引。使用适当的数组方法,如splice
。另外,不要在数组上使用for..in
。