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