JS闭包问题,循环添加事件,只有最后一个

JavaScript013

JS闭包问题,循环添加事件,只有最后一个,第1张

o[i].onclick = (function(n1,p1,s1){

    if (n1.innerHTML == "...展开") {

    n1.innerHTML = "收起"

    p1.innerHTML = s

    } else if(n1.innerHTML == "收起"){

    n1.innerHTML = "...展开"

    p1.innerHTML = s1.substring(0, 30)

    }

})(n,p,s)

1、js没有块级作用域,定义的i变量属于函数n中的变量,在函数n中可以访问到;

2、函数n中主要涉及两个执行环境: arr[]中保存的函数中的局部环境,函数n的局部环境。相应的作用域链为:arr[]中的函数的变量对象->函数n的变量对象。arr[]中的函数在执行时,作用域链向上查找,自身的变量对象中没有i这个变量,继续向上查找函数n的变量对象,而在经历三次循环后,此时i的值已经是3,所以值为3.

3、如果要让i为相应的数值,应该延长作用域链,使用匿名函数构造块级作用域,方法如下:

function n(){

    var arr = []

    for(var i = 0 i < 3 i++){

       

       // 这里通过匿名函数,传入的参数i是传入的值i的一个副本,会把此时i的值保存下来

       arr[i] = (function (i) {

           return function(){console.log(i)}

       })(i)

    }

    return arr

}

var funs = n()

funs[0]()

funs[1]()

funs[2]()

var result=[]

function foo(){

    var i= 0

    for (i<3i=i+1){

        result[i]=function(){

            alert(i)

        }

    }

}

foo()

result[0]() // 3

result[1]() // 3

result[2]() // 3

这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.

解决的方法之一,是让内部函数在循环创建的时候立即执行,并且捕捉当前的索引值,然后记录在自己的一个本地变量里.然后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值,改进后的代码:

var result=[]

function foo(){

    var i= 0

    for (i<3i=i+1){

        result[i]=(function(j){

            return function(){

                alert(j)

            }

        })(i)

    }

}

foo()

result[0]() // 0

result[1]() // 1

result[2]() // 2