从js的循环问题来看待js的闭包本质
来源:互联网 发布:厦门seo技术 编辑:程序博客网 时间:2024/06/05 07:00
from http://www.cnblogs.com/wenber/p/3632428.html
第一次接触这个问题还是在我刚开始学js的时候,当时就是一头雾水,时隔一年多了,突然又想起了这个问题,在这个春气盎然的周末,我就坐下来研究下并把结果和大家分享下;
先看代码:demo.html
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <meta charset="utf-8"/> 5 <title>闭包循环问题</title> 6 <style type="text/css"> 7 p {background:red;} 8 </style> 9 </head> 10 <body> 11 <p id="p0">段落0</p> 12 <p id="p1">段落1</p> 13 <p id="p2">段落2</p> 14 <p id="p3">段落3</p> 15 <p id="p4">段落4</p> 16 <script type="text/javascript" src="jquery-1.7.js"></script>17 <script type="text/javascript"> 18 ~function test() { 19 for( var i=0; i<5; i++ ) { 20 $("#p"+i).bind("click", function() { 21 alert(i); 22 });23 };24 }()25 </script> 26 </body> 27 </html>
每次循环就为对应的编号段落上添加一个click事件,事件的回调函数是执行一个alert();如果你以前没这么用过的话,估计也会认为单击某个段落就会弹出这个段落相应的编号0,1,2,3,4。但实际上是都是弹出5;
网上已经有很多讨论的博客了,他们给出了很多方法去实现弹出对应的编号。比较易于理解的方法如下:
1,将变量i保存在对应的段落的某个属性上:
1 ~function test() { 2 for( var i=0; i<5; i++ ) { 3 $("#p"+i).bind("click", function() {4 alert($(this).attr("index")); 5 }).attr("index",i);6 };7 }();
2,加一层闭包,i 以函数参数形式传递给内层函数:
1 ~function test() { 2 for( var i=0; i<5; i++ ) { 3 (function(param){ 4 $("#p"+i).bind("click", function() { 5 alert(param); 6 }); 7 })(i); 8 9 };10 }()
当然还有其他一些方法,但是都不太好理解。
而我要探索的是,为什么demo.html中的返回值始终是5。网上的说法是“变量i是以指针或者变量地址方式保存在函数中”,因为只有按照这样理解,才能解释。可是仅仅凭借一个结论怎么才能服众了?
谈到指针或者变量地址这个话题,在C语言中倒是家常便饭了,但是在js这么性感的语言中,除了对象的及其对象属性的引用之外很少用到。一个基本的数据类型居然和指针拉上关系了,这勾起了探索的欲望。
3,试试下面的代码
1 ~function test() { 2 var temp =10;3 for( var i=0; i<5; i++ ) { 4 $("#p"+i).bind("click",function() {5 alert(temp); 6 });7 };8 temp=20;9 }();
它的执行结果是每个段落的弹出都是20,而不是10。说明当我们在单击的那个时候,temp的值已经是20。这是个似乎不需要我来说明,很显然的结果,因为在我们单击之前,temp已经被赋值为20了。4,再看看下面的代码,我们在temp被改变值之前有程序去触发单击事件,弹出的是10;
1 ~function test() { 2 var temp =10; 3 for( var i=0; i<5; i++ ) { 4 $("#p"+i).bind("click",function() { 5 alert(temp); 6 }); 7 if(i===1){ 8 $("#p0").trigger("click"); 9 };10 };11 temp=20;12 }();
这说明我们在绑定$("#p0")的单击事件回调函数本来是要返回10的,当我再次手动去单击p0段落时,弹出20的原因是因为temp的值改变了。也就说明,每次弹出时,访问到的是temp此刻的值,而不是绑定时候的值;这可以说明变量temp确实是以变量地址保存的。扩展开去就是:函数内部访问了与函数同级的变量,那么该变量是常驻内存的。访问该变量实质上是访问的是变量的地址;
通过以上的结论,那么我们可以简单的描述闭包的本质了:在子作用域中保存了一份在父级作用域取得的变量,这些变量不会随父级作用域的销毁而销毁,因为他们已经常驻内存了!
这句话也就说明了闭包的特性了:1:因为常驻内存所以会造成内存泄露 2,只要其他作用域能取到子作用域的访问接口,那么其他作用域就有方法访问该子作用域父级作用域的变量了。
看这样一典型的闭包的例子:
1 function A(){ 2 var a=1; 3 4 function B(){ 5 return a; 6 }; 7 8 return B; 9 };10 11 12 var C=A();//C取得A的子作用域B的访问接口13 console.log(C());//1 C能访问到B的父级作用域中的变量a
以上若有不足之处,欢迎指正,共同进步!
- 从js的循环问题来看待js的闭包本质
- 关于js for循环闭包的问题
- JS的闭包问题
- js的闭包问题
- js循环添加onClick事件--js的闭包
- 关于js中的所谓的for循环典型问题的剖析,通过现象看本质
- 从 ECMAScript 规范来看 JS 的 this 绑定规则
- Js new的本质
- Node.js 的本质
- Node.js的本质
- js中‘!!’的本质
- js数组,循环,闭包问题
- JS循环引用的问题
- js 解决js for 循环中的闭包问题
- 解决JS循环闭包导致索引始终为最后值的问题
- 从汉诺塔问题来看“递归”本质
- 程序员从美学角度来看待编写的代码
- 程序员从美学角度来看待编写的代码
- 【km笔记】java概述
- select poll epoll的区别
- 探索equals()和hashCode()方法
- Java发送Http请求,解析html返回
- 移动namenode、secondarynamenode和jobTracker的节点(使其成为独立节点)
- 从js的循环问题来看待js的闭包本质
- (十三)洞悉linux下的Netfilter&iptables:为防火墙增添功能模块【实战】
- 汉诺塔算法
- Java关键字this、super使用总结
- Android学习之TextView的使用
- 纯析构函数理解
- 批处理设置Java及Tomcat的环境变量
- 棋盘模拟——Emag eht htiw Em Pleh
- hdu 1671 Phone List (字典树)