EventEmitterをちょっと改造

EventEmitterはDOMを使用せずにイベント機能をクラスに与えることが可能なとても便利なクラス。
但し最大の不満はListener登録時にListener内でのthisを指定できない点。
※バージョンは5.2.4

例)リスナーの登録

var eventEmitter = new EventEmitter();
・・・
eventEmitter.addListener('click', this.on_clicked.bind(this));

上記のようにListener登録してしまうとremoveListenerが正しく機能せずにListenerが残ってしまう。
例)リスナーの削除

eventEmitter.removeListener('click', this.on_clicked.bind(this));

これらの問題を対応するためにEventEmitterを以下に従って修正

addListenerの修正

変更前

proto.addListener = function addListener(evt, listener) {
    if (!isValidListener(listener)) {
        throw new TypeError('listener must be a function');
    }

    var listeners = this.getListenersAsObject(evt);
    var listenerIsWrapped = typeof listener === 'object';
    var key;

    for (key in listeners) {
        if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
            listeners[key].push(listenerIsWrapped ? listener : {
                listener: listener,
                once: false
            });
        }
    }

    return this;
};

変更後

proto.addListener = function addListener(evt, listener) {
    if (!isValidListener(listener)) {
        throw new TypeError('listener must be a function');
    }
    // tarumi custom
    var bind_instance = null;
    if(arguments.length > 2){
        bind_instance = arguments[2];
    }
    // tarumi custom

    var listeners = this.getListenersAsObject(evt);
    var listenerIsWrapped = typeof listener === 'object';
    var key;

    for (key in listeners) {
        if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
            listeners[key].push(listenerIsWrapped ? listener : {
                listener: listener,
                // tarumi custom
                instance: bind_instance,
                // tarumi custom
                once: false
            });
        }
    }

    return this;
};

関数:emitEventの修正

変更前

proto.emitEvent = function emitEvent(evt, args) {
    var listenersMap = this.getListenersAsObject(evt);
    var listeners;
    var listener;
    var i;
    var key;
    var response;

    for (key in listenersMap) {
        if (listenersMap.hasOwnProperty(key)) {
            listeners = listenersMap[key].slice(0);

            for (i = 0; i < listeners.length; i++) {
                // If the listener returns true then it shall be removed from the event
                // The function is executed either with a basic call or an apply if there is an args array
                listener = listeners[i];

                if (listener.once === true) {
                    this.removeListener(evt, listener.listener);
                }
                response = listener.listener.apply(this, args || []);

                if (response === this._getOnceReturnValue()) {
                    this.removeListener(evt, listener.listener);
                }
            }
        }
    }

    return this;
};

変更後

proto.emitEvent = function emitEvent(evt, args) {
    var listenersMap = this.getListenersAsObject(evt);
    var listeners;
    var listener;
    var i;
    var key;
    var response;

    for (key in listenersMap) {
        if (listenersMap.hasOwnProperty(key)) {
            listeners = listenersMap[key].slice(0);

            for (i = 0; i < listeners.length; i++) {
                // If the listener returns true then it shall be removed from the event
                // The function is executed either with a basic call or an apply if there is an args array
                listener = listeners[i];

                if (listener.once === true) {
                    this.removeListener(evt, listener.listener);
                }

if(listener.instance===null || listener.instance === 'null' || listener.instance === 'undefined' || listener.instance === undefined){
response = listener.listener.apply(this, args || []);
}
else{
response = listener.listener.apply(listener.instance, args || []);
}


                if (response === this._getOnceReturnValue()) {
                    this.removeListener(evt, listener.listener);
                }
            }
        }
    }

    return this;
};

リスナーの登録の変更

eventEmitter.addListener('click', this.on_clicked,this);

リスナーの削除の変更

eventEmitter.removeListener('click', this.on_clicked);