JavaScript函数重载模拟

我们从结果向实现推,首先看我们要实现什么样的效果:

css(hi,"color","red")
css([hi,hello],"color","red")
css(hi,{"border":"1px solid #000","width":"200px"})
var color = css(hi,"color")


这是很常见的写法,然后看我们希望怎么写:

Overload("css",window,
		 {
			 "object,string,string" : function(el,key,val){
				 el.style[key] = val;
			 }
			 ,"array,string,string" : function(els,key,val){
				 for(var i=0;i<els.length;i++){
					els[i].style[key] = val; 
				 }
			 }
			 ,"object,object" : function(el,kv){
				for(var i in kv){
					el.style[i] = kv[i];	
				}
			 }
			 ,"object,string" : function(el,key){
				 return el.style[key];
			 }
});

接下来,看实现:

/*
	JavaScript函数重载模拟
	name : 函数名
	bind : 函数需要绑定到的对象
	fn_objs : 键值对函数对象,键位以逗号隔开的类型(number,string,object,undefined,boolean,array,*)字符串,其中*为万能类型,值为对应的函数,
	如:{"string,string":function(x,y){},"string,number":functioin(x,y){}}
*/
var Overload = function(name,bind,fn_objs){
	var dict_name = "_"+name+"_dict",dict;
	dict = bind[dict_name] = bind[dict_name] || {};
	
	for(var i in fn_objs){
		dict[i] = fn_objs[i];	
	}
	
	var is_match = function(x,y){
		if(x==y)return true;
		if(x.indexOf("*")==-1)return false;
	
		var x_arr = x.split(","),y_arr = y.split(",");
		if(x_arr.length != y_arr.length)return false;
	
		while(x_arr.length){
			var x_first =  x_arr.shift(),y_first = y_arr.shift();
			if(x_first!="*" && x_first!=y_first)return false;
		}
		return true;
	};
	
	bind[name] = function(){
		var args = arguments,args_len = args.length,args_types=[],args_type,match_fn = function(){};
		for(var i=0;i<args_len;i++){
			var type = typeof args[i];
			type=="object" &&  (args[i] instanceof Array) && (type="array");
			args_types.push(type);
		}
		args_type = args_types.join(",");
		for(var k in dict){
			if(is_match(k,args_type)){
				match_fn = dict[k];
				break;
			}
		}
		return match_fn.apply(this,args);
	};
};

因为采用typeof来动态监测参数类型,而typeof又只能检测到的值只有(number,string,object,undefined,boolean),所以类型的制定只能从这些值中设定,实现中还加入了万能类型"*",由于array属于常用类型, 所以又特别添加了对array类型的支持。

基本原理是:将以类型串为键,函数为值的字典挂到需要绑定的对象上,命名为"_"+fn_name+"_dict",可用bind["_"+fn_name_"_dict"]来访问此对象,接着生成一个函数,在函数里靠判断arguments生成的类型串来从上述字典中匹配到相应的函数。

------------------------------------------------------------------------------------------------------------------

上面的写法 ,始终不好看,有如下改进:

Overload = function(fn_objs){
	var is_match = function(x,y){
		if(x==y)return true;
		if(x.indexOf("*")==-1)return false;
	
		var x_arr = x.split(","),y_arr = y.split(",");
		if(x_arr.length != y_arr.length)return false;
	
		while(x_arr.length){
			var x_first =  x_arr.shift(),y_first = y_arr.shift();
			if(x_first!="*" && x_first!=y_first)return false;
		}
		return true;
	};
	var ret = function(){
		var args = arguments
		,args_len = args.length
		,args_types=[]
		,args_type
		,fn_objs = args.callee._fn_objs
		,match_fn = function(){};
		
		for(var i=0;i<args_len;i++){
			var type = typeof args[i];
			type=="object" && (args[i].length>-1) && (type="array");
			args_types.push(type);
		}
		args_type = args_types.join(",");
		for(var k in fn_objs){
			if(is_match(k,args_type)){
				match_fn = fn_objs[k];
				break;
			}
		}
		return match_fn.apply(this,args);
	};
	ret._fn_objs = fn_objs;
	return ret;
};

String.prototype.format = Overload({
	"array" : function(params){
		var reg = /{(\d+)}/gm;
		return this.replace(reg,function(match,name){
			return params[~~name];
		});
	}
	,"object" : function(param){
		var reg = /{([^{}]+)}/gm;
		return this.replace(reg,function(match,name){
			return param[name];
		});
	}
});
posted @ 2011-03-28 10:44  simayixin  阅读(2448)  评论(2编辑  收藏  举报