一个JS小技巧

我们在开发中通常会遇到这样一种情况,比如我有一个函数

这个函数有个参数,函数的功能就是打印参数中name属性

function showName(obj){
    alert(obj.name);
}

// 调用
var Tom = {name:"Tom"};

showName(Tom); // Tom

此时我有一个需求,需要动态生成一些按钮,点击按钮打印不同人的名字

<html>
<head>
<title></title>
<script type="text/javascript">
<!--
	function showName(obj){
		alert(obj.name);
	}
	
	window.onload = function(){
		
		var Jim = {name:"Jim"};
		var Lucy = {name:"Lucy"};

		var buttons = '<input type="button" value="点击" οnclick="showName(Jim)">'
			   +'<input type="button" value="点击" οnclick="showName(Lucy)">';

		document.body.innerHTML += buttons;
	}
//-->
</script>
</head>
<body>
</body>
</html>

此时点击按钮会报错,因为Jim,Lucy是局部对象,按钮上的showName()函数访问不到,一种解决方法是把他们放到onload函数外面,成为全局对象.

显然这不是一种好方法.那么我们能不能用一个工具辅助下来实现呢

直接上代码吧

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript">
<!--

var FunUtil = (function(){

	var index = 0;
	var handlerStore = []; // 存放方法句柄
	var paramStore = []; // 存放参数

	return {
		// 创建方法字符串
		// scope:作用域
		// methodName:方法名,字符串格式
		// param:参数
		createFun:function(scope,methodName,param){
			var currentIndex = index++; // 创建索引

			// 根据索引储存方法句柄和方法参数
			handlerStore[currentIndex] =  function(param){ 
				scope[methodName](param)
			};			
			
			paramStore[currentIndex] = param;
			
			return 'FunUtil._runFun('+currentIndex+')';

		}
		// 执行方法
		// index:索引.根据这个索引找到方法句柄和方法参数
		,_runFun:function(index){
			var handler = handlerStore[index];
			var param = paramStore[index];
			handler(param);
		}
	};
	
})();

function showName(obj){
	alert(obj.name);
}

window.onload = function(){
	
	var Jim = {name:"Jim"};
	var Lucy = {name:"Lucy"};

	var buttons = '<input type="button" value="点击" οnclick="showName(Jim)">'
			 +'<input type="button" value="点击" οnclick="showName(Lucy)">'
			 // 使用工具
			 +'<input type="button" value="使用工具" οnclick="'+FunUtil.createFun(window,'showName',Jim)+'">'
			 +'<input type="button" value="使用工具" οnclick="'+FunUtil.createFun(window,'showName',Lucy)+'">';

	document.body.innerHTML += buttons;
}
//-->
</script>
</head>
<body>
</body>
</html>

这里我写了一个工具类FunUtil,我们就使用它的一个方法

FunUtil.createFun(scope,methodName,param);

第一个参数是被调用函数的作用域,这里就是window

第二个参数是函数名字,字符串形式,这里就是''showName''

第三个参数是函数参数,这里是Jim,Lucy对象

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

再来说下它的实现原理:

用两个数组分别来保存函数句柄和参数,然后我们通过数组的索引来获取对应的函数句柄和参数

注释已经写的很清楚了.

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

当我写好这个工具的时候发现它并不完美,如果我们要传入多个参数呢

当时脑海中就想到了fun.apply(scope,arr);关于此方法可以网上搜索javascript的call apply

于是就有了下面的改进版

[推荐]

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript">
<!--
/*
 使用方法:
 FunUtil.createFun(scope,'some_mothod_name',obj1);
 FunUtil.createFun(scope,'some_mothod_name',obj1,obj2);
 ...
*/
var FunUtil = (function(){
	
	var index = 0; 
	var handlerStore = []; // 存放方法句柄

	return {		
		// scope:作用域
		// methodName:方法名,字符串格式
		// ...:参数可放多个
		createFun:function(scope,methodName){
			var currentIndex = index++; // 创建索引
			
			var argu = []; // 用来存放多个参数
			// 构建参数
			for(var i=2,len=arguments.length;i<len;i++){
				argu.push(arguments[i]);	
			}

			// 把函数句柄存在数组里
			handlerStore[currentIndex] = (function(scope,methodName,argu){
				// 生成函数调用句柄
				return function(){
					scope[methodName].apply(scope,argu);
				}

			}(scope,methodName,argu));			
			
			return 'FunUtil._runFun('+currentIndex+')';
		}
		// 执行方法
		// index:索引.根据这个索引找到执行函数
		,_runFun:function(index){
			var handler = handlerStore[index];
			handler();// 该函数已经传入了参数
		}
	};
	
})();

function showName(obj1,obj2){
	alert(obj1.name + " and " + obj2.name);
}

window.onload = function(){
	
	var Jim = {name:"Jim"};
	var Lucy = {name:"Lucy"};

	var aa = {name:'aa'};
	var bb = {name:'bb'};

	var buttons = '<input type="button" value="点击" οnclick="showName(Jim)">'
			 +'<input type="button" value="点击" οnclick="showName(Lucy)">'
			 // 使用工具,传入多个参数
			 +'<input type="button" value="使用工具" οnclick="'+FunUtil.createFun(window,'showName',Jim,Lucy)+'">'
			 +'<input type="button" value="使用工具" οnclick="'+FunUtil.createFun(window,'showName',aa,bb)+'">' ;

	document.body.innerHTML += buttons;
}
//-->
</script>
</head>
<body>
</body>
</html>


要说明的都写在注释里面了,核心方法就是scope[methodName].apply(scope,argu);

 

可能这个例子有点简单了,我们再来一个复杂点的,更贴近于实际项目的例子

我这里有个表格控件Grid,我要实现一个修改功能,在页面上生成修改列,点击修改,就可修改信息

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script type="text/javascript">
var FunUtil = (function(){

	var index = 0; 
	var handlerStore = []; // 存放方法句柄

	return {		
		// scope:作用域
		// methodName:方法名,字符串格式
		// ...:参数可放多个
		createFun:function(scope,methodName){
			var currentIndex = index++; // 创建索引
			
			var argu = []; // 用来存放多个参数
			// 构建参数
			for(var i=2,len=arguments.length;i<len;i++){
				argu.push(arguments[i]);	
			}

			// 把函数句柄存在数组里
			handlerStore[currentIndex] = (function(scope,methodName,argu){
				// 生成函数调用句柄
				return function(){
					scope[methodName].apply(scope,argu);
				}

			}(scope,methodName,argu));			
			
			return 'FunUtil._runFun('+currentIndex+')';
		}
		// 执行方法
		// index:索引.根据这个索引找到执行函数
		,_runFun:function(index){
			var handler = handlerStore[index];
			handler();// 该函数已经传入了参数
		}
	};

})();

var Grid = function(){
	this.row = [
		{id:1,name:'Jack'}
		,{id:2,name:'Tom'}
		,{id:3,name:'Lucy'}
	];
}

Grid.prototype.updateData = function(obj){
	// 修改信息,可以跳转到另一个页面或者弹窗
	alert('修改:'+obj.name+',主键ID:'+obj.id);
}

Grid.prototype.sendToBody = function(){
	var html = '';
	for(var i in this.row){
		var obj = this.row[i];
		html += (obj.id + ' ' + obj.name + ' <a href="javascript:void(0)" οnclick="'+FunUtil.createFun(this,'updateData',obj)+'">修改</a><br>');
	}
	document.body.innerHTML += html;

}

window.onload = function(){
	var grid = new Grid();
	grid.sendToBody();
}
</script>
</head>
<body>  
</body>
</html>

这样,一个简单的表格就生成了

FunUtil.createFun(this,'updateData',obj); 这里的this指的是Grid对象,整句话的意思就是调用Grid的'updateData'方法,并传入obj

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值