みかづきブログ その3

3ヶ月つづけてみました。

シンプルな EventDispatcher つくりました

シンプルなEventDispatcherを自作してみました。

仕様としては、

  1. イベント名を渡すとイベントがあるかどうかわかる
  2. イベント名とコールバック関数を渡すとイベントを登録できる
  3. イベント名とコールバック関数を渡すとイベントを削除できる
  4. イベント名(と引数)を渡すとイベントを実行できる

の4点を実現しております。

ソースコード

function EventDispatcher() {
    this._events = {};
}

/**
 *  イベントが登録されているか調べます
 *  @param  {string} eventName // イベント名
 */
EventDispatcher.prototype.hasEventListener = function(eventName) {
    return !!this._events[eventName];
};

/**
 *  イベントを登録します
 *  @param  {string}   eventName // イベント名
 *  @param  {function} callback  // 追加する関数
 */
EventDispatcher.prototype.addEventListener = function(eventName, callback) {
    if (this.hasEventListener(eventName)) {
        var events = this._events[eventName],
            length = events.length,
            i = 0;

        for (; i < length; i++) {
            if (events[i] === callback) {
                return;
            }
        }

        events.push(callback);
    } else {
        this._events[eventName] = [callback];
    }
};

/**
 *  イベントを削除します
 *  @param  {string}   eventName // イベント名
 *  @param  {function} callback  // 削除する関数
 */
EventDispatcher.prototype.removeEventListener = function(eventName, callback) {
    if (!this.hasEventListener(eventName)) {
        return;
    } else {
        var events = this._events[eventName],
            i = events.length,
            index;

        while (i--) {
            if (events[i] === callback) {
                index = i;
            }
        }

        events.splice(index, 1);
    }
};

/**
 *  イベントを発火します
 *  @param  {string} eventName // イベント名
 *  @param  {object} opt_this  // thisの値
 *  @param           opt_arg   // 引数 
 */
EventDispatcher.prototype.fireEvent = function(eventName, opt_this, opt_arg) {
    if (!this.hasEventListener(eventName)) {
        return;
    } else {
        var events     = this._events[eventName],
            copyEvents = _copyArray(events),
            arg        = _copyArray(arguments),
            length     = events.length,
            i = 0;

        // eventNameとopt_thisを削除
        arg.splice(0, 2);

        for (; i < length; i++) {
            copyEvents[i].apply(opt_this || this, arg);
        }
    }

    function _copyArray(array) {
        var newArray = [],
            i = 0;

        try {
            newArray = [].slice.call(array);
        } catch(e) {
            for (; i < array.length; i++) {
                newArray.push(array[i]);
            }
        }

        return newArray;
    }
};

つかいかた

継承してつかってください。

function Hey() {
    EventDispatcher.call(this);
}

Hey.originalConstructor = Hey.prototype.constructor;
Hey.prototype = new EventDispatcher();
Hey.prototype.constructor = Hey.originalConstructor;

var hey = new Hey();

hey.addEventListener("say", function(evt) {
    alert(evt);
});

hey.fireEvent("say", hey, "jump!");

demo