二. 闭包的应用
应用1:
这个是我在用js模拟排序算法过程遇到的问题。我要输出每一次插入排序后的数组,如果在循环中写成
setTimeout(function() { $("proc").innerHTML += arr + "<br/>"; }, i * 500);
会发现每次输出的都是最终排好序的数组,因为arr数组不会为你保留每次排序的状态值。为了保存会不断发生变化的数组值,我们用外面包裹一层函数来实现闭包,用闭包存储这个动态数据。下面用了2种方式实现闭包,一种是用参数存储数组的值,一种是用临时变量存储,后者必须要深拷贝。所有要通过闭包存储非持久型变量,均可以用临时变量或参数两种方式实现。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"><!-- var arr = [4, 5, 6, 8, 7, 9, 3, 2, 1, 0]; var $ = function(id) { return document.getElementById(id); } var Sort = { Insert: function() { for (var i = 1; i < arr.length; i++) { for (var j = 0; j < i; j++) { if (arr[i] < arr[j]) { arr[i] = [arr[j], arr[j] = arr[i]][0]; } } setTimeout((function() { var m = []; for (var j = 0; j < arr.length; j++) { m[j] = arr[j]; } return function() { $("proc").innerHTML += m + "<br>"; } })(), i * 500); //or 写成下面这样也可以 /* setTimeout((function(m) { return function() { $("proc").innerHTML += m + "<br>"; } })(arr.join(",")), i * 500); */ } return arr; } } // --></script> </head> <body> <div> var a = [4, 5, 6, 8, 7, 9, 3, 2, 1, 0];</div> <div> <input type="button" value="插入排序" onclick="Sort.Insert();" /> </div> Proc: <div id="proc"> </div> </body> </html>
应用2:
这个是无忧上的例子(点击这里查看原帖),为每个<li>结点绑定click事件弹出循环的索引值。起初写成
id.onclick = function(){ alert(i); } id.onclick = function(){alert(i);}
发现最终弹出的都是4,而不是想要的 1、2、3,因为循环完毕后i值变成了4。为了保存i的值,同样我们用闭包实现:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"><!-- window.onload = function() { for (var i = 1; i < 4; i++) { var id = document.getElementById("a" + i); id.onclick = (function(i) { return function() { alert(i); } })(i); } } // --></script> </head> <body> <ul> <li id="a1">aa</li> <li id="a2">aa</li> <li id="a3">aa</li> </ul> </body> </html>
应用4:
这个是无忧上月MM的例子(点击这里查看原帖),用闭包实现程序的暂停执行功能,还蛮创意的。
<input type="button" value="继续" onclick='st();'/> <script type="text/javascript"><!-- var st = (function() { alert(1); alert(2); return function() { alert(3); alert(4); } })(); // --></script>
把这个作用延伸下,我想到了用他来实现window.confirm。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"> var $ = function(id) { return "string" == typeof id ? document.getElementById(id) : id; } var doConfirm = function(divId) { $(divId).style.display = ""; function closeDiv() { $(divId).style.display = "none"; } return function(isOk) { if (isOk) { alert("Do deleting..."); } closeDiv(); } } </script> <style type="text/css"> body { font-family: Arial; font-size: 13px; background-color: #FFFFFF; } #confirmDiv { width: 200px; height: 100px; border: dashed 1px black; position: absolute; left: 200px; top: 150px; } </style> </head> <body> <div> <input name="btn2" type="button" value="删除" onclick="doConfirm('confirmDiv');" /> <div id="confirmDiv" style="display: none;"> <div style='position: absolute; left: 50px; top: 15px;'> <p> 你确定要删除吗?</p> <input type="button" value="确定" onclick="doConfirm('confirmDiv')(true);" /> <input type="button" value="取消" onclick="doConfirm('confirmDiv')(false);" /> </div> </div> </div> </body> </html>
看了上面的这些应用,再回到前面的一句话:在动态执行环境中,数据实时地发生变化,为了保持这些非持久型变量的值,我们用闭包这种载体来存储这些动态数据。这就是闭包的作用。也就说遇到需要存储动态变化的数据或将被回收的数据时,我们可以通过外面再包裹一层函数形成闭包来解决。
当然,闭包会导致很多外部函数的调用对象不能释放,滥用闭包会使得内存泄露,所以在频繁生成闭包的情景下我们要估计下他带来的副作用。
毕了。希望能对大家有所帮助。
者:JayChow
出处:http://ljchow.cnblogs.com