JS中如何解决for循环中的延迟执行问题

JavaScript016

JS中如何解决for循环中的延迟执行问题,第1张

我们先来看一个例子

在JS方法里面设置一个for循环,输出每次循环的值,如下图

我们可以根据闭包的知识来更改一下for循环中的逻辑,利用闭包将i的值传递给a

这次在运行程序我们就可以看到输出内容是0开始输出了

结果如下图

JS中如果for循环中有异步方法,就需要用闭包的方式保留当前循环变量值

学习记录,别提问,我可能答不上来!^-^。。。

1.预编译

我们的需求是希望输出0-9 依次输出 0 1 2 3 4 5 6 7 8 9 ,但是这个输出的是十个10;

为什么是十个10呢,因为test()函数内循环时,arr[i]是被赋值为一个函数体,该函数体并没有执行,所以console.log(i)中的i并没有随着arr[i]中的i一起改变,然后被保存到外部myArr,myArr就是一个数组,里面有10个函数,myArr[j]()就是来调用myArr中的函数运行。当myArr[j]()函数运行console.log(i)时,这个i访问的是test()的AO。

上文说到arr[i]并没有运行,test()中for循环i=10时不满足循环条件,退出循环,这时 test()的AO对象中i就等于10了,在test()函数结束之前,arr被返回到函数外部,这个myArr就继承了test() 的AO对象。至此test()执行完毕,释放AO对象。重点来了,test()的AO 对象释放了,但是!myArr在test()结束之前继承了test()的AO对象,所以test()的AO对象被myArr拿到了手中,没想到吧!!所以在myArr循环输出console.log(i)时,这个i实际输出的是test()AO中的i,这个i在test()循环结束时等于10,所以外部循环调用输出console.log(i),循环10次,输出的就是10个10。好晕!看图:

匿名函数自调会立即执行,让i作为实参,j为形参,函数声明执行前都会预编译生成AO, 形参实参统一,每执行一次形参j都会跟实参 i 改变;循环结束后arr中就相当于放了10个匿名函数自调,并引用了匿名函数自调的AO,每一个AO中j都根据i而累加了,所以在外部调用输出j时,就再这个匿名函数自调中找j,输出就达到我们要的效果啦。下图是arr中匿名函数的AO,每一个j都根据i改变:

至此就完美的解决闭包问题啦!!

学习记录,有写错的地方可以指出改正^-^

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]()