先看一下代码:
<ul>
<li>1111</li>
<li>2222</li>
<li>3333</li>
</ul>
<script>
var a=document.getElementsByTagName('li');
for(var i=0,l=a.length;i<l;i++){
a[i].οnclick=function(){
alert(i)
}
}
</script>
一个最经典的例子,上面的代码无论点击哪个结果都为最后的值,因为click事件接收的函数形成了一个闭包,闭包里的i只是对外部函数中变量i的引用,当fn执行完毕时变量i是循环得出的最后的值,闭包内的变量i也就是这个值了,所以不会依次弹出1,2,3。
至于解决的方法:
1. 为遍历的每个元素添加自定义属性用来保存当前的索引值。
function fn() {
var a = document.getElementsByTagName("li ");
for( var i=0; i<a.length; i++ ) {
a[i].i = i;
a[i].onclick = function() {
alert(this.i);
}
}
}
2. 将当前索引值保存到匿名函数自身。
function fn() {
var a = document.getElementsByTagName("li");
for( var i=0; i<a.length; i++ ) {
(a[i].onclick = function() {
alert(arguments.callee.i);
}).i = i;
}
}
3. 加一层闭包,将当前索引值以函数参数形式传递到内部函数。
function fn() {
var a = document.getElementsByTagName("li");
for( var i=0; i<a.length; i++ ) {
(function(arg){
a[i].onclick = function() {
alert(arg);
};
})(i);//调用时参数
}
}
4. 加一层闭包,将当前索引值以变量形式传递到内不函数。
function fn() {
var a= document.getElementsByTagName("li");
for( var i=0; i<a.length; i++ ) {
(function () {
var index = i;//调用时局部变量
a[i].onclick = function() {
alert(index);
}
})();
}
}
5. 加一层闭包,返回一个函数作为响应事件。
function fn() {
var a = document.getElementsByTagName("li");
for( var i=0; i<a.length; i++ ) {
a[i].onclick = function(arg) {
return function() {//返回一个函数
alert(arg);
}
}(i);
}
}
6. 利用Function对象,需要注意的是Function构造函数是在脚本运行时创建函数并将参数用作新函数的参数,所以相对前几种方法执行效率较低。
function fn() {
var a = document.getElementsByTagName("li");
for( var i=0; i<a.length; i++ ) {
a[i].onclick = Function('alert('+i+')')
}
}
7. 利用Function对象实例来产生闭包。
function fn() {
var a= document.getElementsByTagName("li");
for( var i=0; i"a.length; i++ ) {
a[i].onclick = new Function('alert(' +i+' )' );//new一次就产生一个函数实例
}
}
【原文地址】 http://www.nowamagic.net/javascript/js_UnderstandJavascriptClosure.php