一个JS小技巧

来源:互联网 发布:美版a1453支持什么网络 编辑:程序博客网 时间:2024/05/16 20:28

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

这个函数有个参数,函数的功能就是打印参数中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="点击" onclick="showName(Jim)">'   +'<input type="button" value="点击" onclick="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="点击" onclick="showName(Jim)">' +'<input type="button" value="点击" onclick="showName(Lucy)">' // 使用工具 +'<input type="button" value="使用工具" onclick="'+FunUtil.createFun(window,'showName',Jim)+'">' +'<input type="button" value="使用工具" onclick="'+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="点击" onclick="showName(Jim)">' +'<input type="button" value="点击" onclick="showName(Lucy)">' // 使用工具,传入多个参数 +'<input type="button" value="使用工具" onclick="'+FunUtil.createFun(window,'showName',Jim,Lucy)+'">' +'<input type="button" value="使用工具" onclick="'+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)" onclick="'+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
原创粉丝点击