JavaScript闭包 循环输出i

html

<body>     
<p>产品一</p>     
<p>产品二</p>     
<p>产品三</p>     
<p>产品四</p>     
<p>产品五</p>     
</body> 

js

function init() {     
    var pAry = document.getElementsByTagName("p");     
    for( var i=0; i<pAry.length; i++ ) {     
         pAry[i].onclick = function() {     
         alert(i);     
    }     
  }     
}  
window.onload = init;

上面代码点击每个p,输出都是5,因为这里的 i 是个引用。演示地址

要想输出对应的i,有以下方法:

1、将变量 i 保存给在每个段落对象(p)上

function init() {
    var pAry = document.getElementsByTagName("p");
    for (var i = 0; i < pAry.length; i++) {
        pAry[i].i = i;
        pAry[i].onclick = function() {
            alert(this.i);
        }
    }
}
window.onload = init;

演示地址

2、将变量 i 保存在匿名函数自身

function init() {
    var pAry = document.getElementsByTagName("p");
    for (var i = 0; i < pAry.length; i++) {
        (pAry[i].onclick = function() {
            alert(arguments.callee.i);
        }).i = i;
    }
}
window.onload = init;

演示地址

caller返回一个函数的引用,这个函数调用了当前的函数;

callee返回正在执行的函数本身的引用,它是arguments的一个属性

3.加一层闭包,i以函数参数形式传递给内层函数

function init() {
    var pAry = document.getElementsByTagName("p");
    for (var i = 0; i < pAry.length; i++) {
        (function(arg) {
            pAry[i].onclick = function() {
                alert(arg);
            };
        })(i); //调用时参数     
    }
}
window.onload = init;

演示地址

4、加一层闭包,i以局部变量形式传递给内存函数

function init() {
    var pAry = document.getElementsByTagName("p");
    for (var i = 0; i < pAry.length; i++) {
        (function() {
            var temp = i; //调用时局部变量     
            pAry[i].onclick = function() {
                alert(temp);
            }
        })();
    }
}
window.onload = init;

演示地址

5、加一层闭包,返回一个函数作为响应事件(注意与3的细微区别)

function init() {
    var pAry = document.getElementsByTagName("p");
    for (var i = 0; i < pAry.length; i++) {
        pAry[i].onclick = function(arg) {
            return function() { //返回一个函数     
                alert(arg);
            }
        }(i);
    }
}
window.onload = init;

演示地址

6、用Function实现,实际上每产生一个函数实例就会产生一个闭包

function init() {
    var pAry = document.getElementsByTagName("p");
    for (var i = 0; i < pAry.length; i++) {
        pAry[i].onclick = new Function("alert(" + i + ");"); //new一次就产生一个函数实例    
    }
}
window.onload = init;

演示地址

7、用Function实现,注意与6的区别

function init() {
    var pAry = document.getElementsByTagName("p");
    for (var i = 0; i < pAry.length; i++) {
        pAry[i].onclick = Function('alert(' + i + ')')
    }
}

window.onload = init;

演示地址

看了这篇文章,又想到用es5,es6的两个方法:

8、用es5 forEach函数

这里用forEach也行成了一个所谓的闭包,forEach里的执行函数也行成了一个闭包,每个执行体里,index都是一局部作用域,那为什么用Array.from呢,我们也可以用[].slice.call(node)我们类数组对象转化成真正的数组

function init() {     
    var pAry = document.getElementsByTagName("p"); 
    //pAry = Array.from(pAry); 
    pAry = Array.prototype.slice.call(pAry);           
    pAry.forEach(function(currentItem,index){
      currentItem.onclick = function(){
        alert(index);
      }
    })    
  }     
window.onload = init;

演示地址

9、用es6的let声明块级变量

function init() {     
    var pAry = document.getElementsByTagName("p");     
    for( let i=0; i<pAry.length; i++ ) {     
         pAry[i].onclick = function() {     
         alert(i);     
    }     
  }     
}  
window.onload = init;

演示地址

知乎关于这个问题也有一些回答
https://www.zhihu.com/question/33468703

原文地址:https://www.cnblogs.com/fazero/p/6752771.html