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