Javascript class 系统使用原型
Javascript class system using prototypes
我正在尝试使用函数和原型在 JS 中创建一个 'class like' 继承系统。
这个想法是在没有整个框架开销的情况下实现类似于 ExtJS class 系统的东西。
所以现在我创建了一个 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
创建一个 'subclass' 并创建它的新实例,它们都共享对
listeners
属性.
因此,如果我向子class 实例 (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
中的另一个原型。有人可以帮我吗?
谢谢
为了回答您的问题,您在原型 上设置了 属性 listeners
,因此它由所有实例共享。您的构造函数需要在每个实例对象上创建此 属性。
function ObjectBase() {
this.listeners = [];
this.parent = 'none'; // you have `parent: none` which will error as `none` is undefined
}
顺便说一句,不要使用 delete
从数组中删除元素;你会弄乱索引。使用适当的数组方法,如 splice
。另外,不要在数组上使用 for..in
。
我正在尝试使用函数和原型在 JS 中创建一个 'class like' 继承系统。 这个想法是在没有整个框架开销的情况下实现类似于 ExtJS class 系统的东西。
所以现在我创建了一个 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
创建一个 'subclass' 并创建它的新实例,它们都共享对
listeners
属性.
因此,如果我向子class 实例 (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
中的另一个原型。有人可以帮我吗?
谢谢
为了回答您的问题,您在原型 上设置了 属性 listeners
,因此它由所有实例共享。您的构造函数需要在每个实例对象上创建此 属性。
function ObjectBase() {
this.listeners = [];
this.parent = 'none'; // you have `parent: none` which will error as `none` is undefined
}
顺便说一句,不要使用 delete
从数组中删除元素;你会弄乱索引。使用适当的数组方法,如 splice
。另外,不要在数组上使用 for..in
。