JS用イベントドリブン実装に必須EventDispatcher作ったよ(this固定機能付)

必要になったので作ってみた。
this固定してdispatchできるよ!



ちゃちゃっとさっき作ったばっかなので、ほとんどテストしてません・・・
多分平気!
とりあえずFireFoxで必要だったのでIEとかでは動かしてもないので動かないかも。




Class.create();の部分だけprototype.js使ってるので、prototype.jsつかってなければ書き換えてください。

コード

//EventDispatcher.js
/**
 * EventDispatcher
 * @author kaw
 */
var EventDispatcher = Class.create();
EventDispatcher.prototype = {
	/**
	 * 
	 * @type Array
	 */
	_targetList:null,
	
	/**
	 * Constructor
	 * @param {} subClassInstance
	 * @usage
	 *         new EventDispatcher( this );
	 */
	initialize:function( subClassInstance ){
		this._targetList = new Array();
		var reference    = this;
		subClassInstance.dispatchEvent       = function( ){
			reference.dispatchEvent.apply( reference , arguments );
		}
		subClassInstance.addEventListener    = function( ){
			reference.addEventListener.apply( reference , arguments );
		}
		subClassInstance.removeEventListener = function( ){
			reference.removeEventListener.apply( reference , arguments );
		}
	},
	
	/**
	 * イベントを発行します.
	 * @param String event
	 * @param {} broadCastObject
	 * @usage
	 *         this.dispatchEvent( "change" , { id:1212 , type:"AAAA" } );
	 */
	dispatchEvent:function( event , broadCastObject ){
		if( this._targetList[event] == undefined ){
			return;
		}
		var list = this._targetList[event];
		var len  = list.length;
		for( var i = 0 ; i < len ; i++ ){
			var o       = list[i];
			var handler = o['handler'];
			var ref     = o['ref'];
			if( ref == undefined ){
				handler( broadCastObject );
			}else{
				handler.apply( ref , [ broadCastObject ] );
			}			
		}
	},
	
	/**
	 * イベントを追加します.
	 * @param String event
	 * @param Function handler
	 * @param {} ref 必須ではありませんが指定すると、コールバック先のthis参照がrefで固定されます.
	 * @usage
	 *         target.addEventListener( "change" , this._onChanged , this );
	 */
	addEventListener:function( event , handler , ref ){
		if( this._targetList[event] == undefined ){
			this._targetList[event] = new Array();
		}
		/*
		var list = this._targetList[event];
		var len  = list.length;
		for( var i = 0 ; i < len ; i++ ){
			var o       = list[i];
			var _handler = o['handler'];
			if( _handler == handler ){
				//登録済み.
				return;
			}
		}
		*/
		this.removeEventListener( event , handler );
		this._targetList[event].push( { handler:handler , ref:ref } );
	},
	
	/**
	 * イベントを削除します.
	 * @param String event
	 * @param Function handler
	 * @usage
	 *          target.removeEventListener( "change" , this._onChanged );
	 */
	removeEventListener:function( event , handler ){
		if( this._targetList[event] == undefined ){
			return;
		}
		var list = this._targetList[event];
		var len  = list.length;
		for( var i = 0 ; i < len ; i++ ){
			var o       = list[i];
			var _handler = o['handler'];
			if( _handler == handler ){
				list.splice( i , 1 );//delete
				return;
			}
		}
	}
}


/**
 * EventDispatcherに対象のオブジェクトを追加します.
 * @param {} obj
 * @usage
 *         EventDispatcher.register( this );
 */
EventDispatcher.register = function( obj ){
	return new EventDispatcher( obj );
}

使い方

var TestEventDispatcher = Class.create();
TestEventDispatcher.prototype = {
	initialize:function(){
		//イベントDispatcherに登録
		EventDispatcher.register( this );
	},
	callTestDummyEvent:function(){
		//イベントのdispatch
		this.dispatchEvent(  "testDummyEvent" , ">>>ここにはオブジェクトとかdispatch先の引数に渡したいものを指定できますよ!" );
	}
}

var Test = Class.create();
Test.prototype = {
	_member:null,
	initialize:function( value ){
		this._member = value;
		
		var testEventDispatcher = new TestEventDispatcher();
		//リスナーの登録
		//第三引数にコールバック先でthisを固定する参照を渡すことができます
		testEventDispatcher.addEventListener( "testDummyEvent" , this._onChanged , this );
		
		//Test!!
		testEventDispatcher.callTestDummyEvent();
	},
	_onChanged:function( event ){
		alert( "値のdispatchできてる?? >> " + event );//値のdispatchできてる?? >> ここにはオブジェクトとかdispatch先の引数に渡したいものを指定できますよ!
		alert( "thisとおってる?? >> " + this._member );//thisとおってる?? >> Hello!
	}
}
new Test( "Hello!" );