本文深入解析JavaScript闭包机制,通过经典DOM事件绑定案例,说明循环中变量共享导致的值捕获错误。详细阐述如何利用立即执行函数(IIFE)创建局部作用域,从而正确捕获循环变量值,解决闭包常见陷阱。
闭包概念与问题背景
本文通过具体实例解析JavaScript中的闭包概念,供读者参考学习。
此前,我花费大量时间阅读书籍中关于闭包的论述,并参考了多篇相关博客文章,自认为已经掌握了这一概念。
然而,下午在QQ群中有人提出了一道经典的闭包题目,如下图所示:

我建议对方查阅书籍中的闭包章节。随后,我决定亲自尝试解答,本以为耗时不多,但实际编写过程中却遇到了困难,迟迟无法得出正确结果。
最终,通过重新研读书籍内容并进行自我总结,我认为这次真正理解了闭包的原理。如果下次仍无法理解,那便需要深入反思了。
-----------------------------------分割线-----------------------------------分割线--------------------------
首先,我们需要明确几个核心概念:
立即执行函数:形如 (function(){})();的一类函数;
闭包:闭包是指有权访问另一函数作用域中的变量的函数。
作用域链:当代码执行的时候,会创建变量对象的一个作用域链....(具体百度)
问题代码分析与作用域查找机制
针对上述问题,我重新编写了示例代码,源码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>闭包经典例子详解——huansky</title>
</head>
<body>
<div id="ttt">
<p >000000000000000000</p>
<br>
<p >111111111111111111</p>
<br>
<p >222222222222222222</p>
</div>
</body>
<script>
var dom=document.getElementsByTagName("p");
for(var i=0;i<dom.length;i++){
dom[i].onclick=function(){
console.log(i);//3
};
}
</script>
</html>
首先,代码中的匿名函数没有变量 i,所以它必须向上查找,在全局环境中找到了 i。
当for循环运行后,全局变量中的 i 变成了3。此时当你点击文字的时候,会调用其绑定的函数,而该函数运行的时候,发现自己没有 i,就会取得全局环境中的 i。
所以,最后的结果是,不管你点击那段文字,最后结果都是3。
PS:感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码,看看运行效果。
利用立即执行函数解决闭包问题
那怎么办呢?你可以用立即执行函数,看代码:
for(var i=0;i<dom.length;i++){
dom[i].onclick=function(i){
return function( ){
console.log(i);
};
}(i);
}
我们把参数 i 作为传给立即执行函数,这样,i 的值就传给了立即执行函数的局部变量 i 了。立即执行函数会直接执行,但是其活动不会销毁,因为里面有个匿名函数。执行后局部变量 i 与全局变量 i 联系就切断了,也就是执行的时候,传进去的变量 i 是多少,立即执行函数的局部变量 i 就是多少,并且该局部变量 i 仍然没有消失,因为匿名函数的存在。
这时候,return中的匿名函数的作用域链中会有两个变量 i。当点击文本的时候,它向上搜索 i 的时候,它找到立即执行函数的局部变量 i ,就停止向上查找了,因此最后的结果就不会是全局变量 i 的值3了。
有一个方法可以检验你们有没有真的理解上面所说的,看上面的变体,代码:
for(var i=0;i<dom.length;i++){
dom[i].onclick=function(t){
return function( ){
console.log(t);//1
console.log(i);//3
};
}(i);
}
其实return中的匿名函数中的 t 就是立即执行函数的局部变量 i,而 i 就是 指全局变量 i,因为立即执行函数中没有变量i,只能继续向上搜索,然后就找到全局变量的 i 了。
如果看到这里,你还没有理解,有两个原因:一个原因是我表达的不够好,另一个原因是你没有完全理解前面提到的这些概念,还要继续看书。
更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》
希望本文所述对大家JavaScript程序设计有所帮助。