js闭包

末鹿安然 提交于 2020-11-08 18:51:10
昨天接触到的一些问题让我对js闭包有了更深刻的理解。
现在我将问题的“上下文”详细说一下:
我要实现一个页面,让管理员对用户的权限进行管理,页面如下:


 

 

 


我要实现的效果是:当管理员单击下拉列表对用户的审核状态进行更改之后,将要修改的用户id和目前审核状态发送至后台,在后台处理完之后将信息反馈给前端,并进行一些提示,效果如图:

 

 

 


将提示信息显示在被处理用户信息同一行的一个单元格里面。
简单的思路:用jquery.post也好xmlhttprequest.open也好,当管理员对某一行的审核状态进行修改的时候,收集用户编号和修改后的审核状态,发送给后台,后台将处理的结果反馈回来,当前端得到后台的反馈之后,执行事先定义的回调函数,进行相应的提示操作:

jQuery.post(
    url,
    {id:2,state:good},
    function(){
      //more cord……
    }
);

问题的关键来了,从服务器反馈的信息可以知道要显示操作成功还是操作失败,但是,你要在表格里面显示提示信息,至少要知道提示信息要显示在第几行吧,然而后台并不是万能的,这么“前端”的问题,就不要为难后台了。
也许你会说,那就定义一个js的全局变量,记录管理员操作的记录是哪一行的,到时候后台反馈了就能直接定位显示了,好吧,这个暂时是解决了,假如,这个管理员的手很快,而后台的反应很慢,管理员处理了五六个,后台才返回其中一个的处理信息呢?也许你又会说,定一个数组吧,存放被处理的行号,然后要求后台在返回处理结果的同时也返回id,然后balabalabala捣鼓一下就能显示了⊙﹏⊙b,咱能不能有点追求呀。

好了引出我要说的主题js闭包,上面的问题,在我看来比较顺眼的处理方式是:在每一个给jquery.post或xmlhttprequest.open注册回调函数的时候,将对应要显示提示信息的label或是span也一并传进去,执行回调的时候就很方便啦,于是乎有了以下面的初步成果:

function callback(value){
 alert(value);
}

jQuery.post(
    url,
    {id:2,state:good},
    callback("helloworld");
);

但是发现只要jQuery.post方法一执行,就马上弹出helloworld的对话框,照我的理解,诸如函数名后面加个括号:functionName(),就等于是函数调用,执行到那里就直接调用了(个人理解,仅供参考),好了虽然这个方法不行,但大概明确了目标,要将一个值传给一个函数,而在传的同时这个函数得等到我们需要的时候才能执行,使用闭包就能实现这个效果了:

function parent_fun(value){
 var name=value;
 function child(){
  alert(name);
 }
 return child;
}

function test(){
 var fun=parent_fun("helloword");
 fun();
}

parent_child函数定义了一个局部变量name和一个函数child,然后将child函数返回出去,在执行了parent_child("helloword")之后就会得到返回的child函数,同时child函数的alert(name);这句中的name还是指向父函数parent_child的局部变量name,而在child函数被返回的时候,child并没有被执行,这个过程下来之后就大概达到了我们之前的目的了,child函数中使用的参数是我们预先传给parent_child的,而且child函数的执行也是可以由我们控制的。
这其中的原理我不是很清楚, 就引用网上其他网友的一段话吧:
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

原文地址
实现上面
现在将全部代码贴出来:
首先是table的html代码:
    
<table > //方便起见只有一行
	<tr>
	    <th>编号</th>  <th>用户名</th>   <th>审核状态</th>
	</tr>
	<tr>
	    <td>1</td>
	    <td>jim</td>
	    <td>
		<select onchange="change(this)">		
		    <option value=0>审核通过</option>
		    <option value=1>审核不通过</option>
		</select>
                <span></span>   //这里是放置提示信息的地方!!!!!
	    </td>
	</tr>	
</table>

然后是js代码:
//当select的onchange事件触发之后执行的函数
function change(mySelect){
     var myTr=$(mySelect).parent().parent();//获取到select所在的行tr元素
     var mySapn=myTr.find("span")[0]; //查找到所在行的span元素
     var id=myTr.find("td")[0].innerHTML; //获取用户编号
     var shenhe=mySelect.value; //获取审核状态
     var callback=callback_parent(mySelect); //将要显示提示信息的span传进去,得到回调函数
     jQuery.post(
                    url, //请求的url
                    {ID:id,ShenHe:shenhe}, //请求的参数
                    function(data){      //回调函数
                        callback(data);
                    }
                );
}

//获取jQuery.post中后台数据回传后执行的回调函数
function callback_parent(arg){
    var mySpan=arg;
    function callback(msg){
        $(mySpan).attr("innerHTML",msg);//根据传入的参数,更改对应span的显示信息
    }
    return callback; //将函数返回
}

还有一种方式可以实现上面的效果,试想,开辟一个地方,可以容纳一些属性,和方法,然后需要的时候可以调用这些方法同时使用那些属性,这些特征很像对象,在js中也能自己定义对象,比如:
var o={
  name:"雷锋",
  info:"助人为乐"
}

那么上面也能用下面的方法来实现:
//当select的onchange事件触发之后执行的函数
function change(mySelect){
     var myTr=$(mySelect).parent().parent();//获取到select所在的行tr元素
     var mySapn=myTr.find("span")[0]; //查找到所在行的span元素
     var id=myTr.find("td")[0].innerHTML; //获取用户编号
     var shenhe=mySelect.value; //获取审核状态
     var callbackObject={       //这里是不一样的地方             span_:mySpan,
            callback:function(msg){
                $(this.span_).attr("innerHTML",msg); //这里使用this.span_调用
            }
          };
     jQuery.post(
                    url, //请求的url
                    {ID:id,ShenHe:shenhe}, //请求的参数
                    function(data){      //回调函数
                        callbackObject(data); //这里没有什么变化
                    }
                );
}

但是这样做的缺点也是明显的,就是不能重用,如果你有很多地方都要使用这个回调函数,那么每个地方都要重新写过了,如果只是临时使用,这个也不失为一个好方法



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!