在JS里有关于闭包的一些问题
1 问题描述
首先我们先来欣赏一段代码
function test() { var arr = []; for(var i = 0; i < 10; i ++){ arr[i] = function (){ document.write(i + " "); } } return arr; } var Myarr = test(); for(var j = 0; j < 10; j ++){ Myarr[j](); } |
我们首先定义了一个test函数,然后在这个函数里面定义了一个数组,再通过for循环给数组里面的每一位变成一个函数,作用就是打印当前i的值。再然后return这个数组,最后在test函数外部定义Myarr,就等于test函数的执行结果,最后再执行Myarr数组的每一位。按之前的理解是执行的结果应该是0-9十个数字。但是实际结果是十个10.
2 问题分析
我们先来分析,为什么会打印出10,按道理说应该是9。问题就在于第一个for循环,i从1执行到了9,此时又重新开始一次循环,此时9<10,所以i就变成10了。但是此时i不满足for循环了,所以不执行里面的函数了。我们可以用以下代码解释
for(var i = 0; i < 10 ; i ++){ document.write(i) } document.write(i) |
我们再来看为什么会输出10个10呢。这个问题在于arr[i] = function (){document.write(i + " ")。代码在执行for循环的时候,前面i的值发生变化,但是在后面的这个function里面的i并不会发生变化,因为在循环的时候这个function只是一个赋值语句,它并不会去看里面的内容,只有在最后调用Myarr的时候在来看里面的内容,而此时i的值已经全部循环结束变成10了。那我们要是想要它输出0-9十个数字怎么办呢?
3 解决方案
此时闭包已经形成了,闭包也分好的和不好的,出现这种情况就属于不好的。那么我们要怎么去避免呢。我们想要的就是for循环里面的function里的i能够跟随外面的i一起变化。此时我们可以采用立即执行函数,完整代码如下
<script> function test() { var arr = []; for(var i = 0; i < 10; i ++){ (function (j) { arr [j] = function () { document.write(j + " "); } }(i)); } return arr; } var Myarr = test(); for(var j = 0; j < 10; j ++){ Myarr[j](); } </script> |