这是《JavaScript高级程序设计》181页一个闭包的例子:
function createFunctions(){ var result = new Array(); for(var i = 0; i < 10; i++){ result[i] = function(){ return i; } } return result; }
结果并不是每个函数都返回自己的索引值,而是每个函数都返回10,这是为什么?
其中书中这段代码上方一段文字种有这么一句话:
别忘了闭包所保存的是整个变量对象,而不是某个特殊变量。
请问这句话又是什么意思?谢谢各位
i
变量只有一个,保存在作用域链中没有被销毁(因为闭包还在使用),所以,results[i]
中每一个函数中的i
变量始终都指向同一个变量。所以在for
循环以后,i
变量就变成了10
,当执行闭包的时候,每一个函数去作用域链上找i
变量,得到的结果就是10
这里的i是个变量引用,循环完后i变成了10,返回的i全部指向10.
主要是变量作用域的问题。
for中的i的声明可以理解等价于:
循环中的匿名函数return的是i 而不是1,2,3
所以最终i的值是多少就return多少。
如果最后把i赋值为0, 函数返回就都是0, 就像:
所以写一个立即执行函数把当时的i保留下来,匿名函数return的就是当时i的值了。
es6有let关键字, for中的var改成let可以替代闭包,如果是新建的nodejs的项目已经可以无视这个问题了,可以说是js的遗留的变量作用域问题
var i 定义在函数createFunctions中,循环结束后i变成了10,其他所有新建的函数都是return 语句中引用同一个i,所以都返回10.
看下MDN
result[i]是个function。只是一个别名,并不是该function执行后返回的结果
这里是return i,而最后i的值为10,当然结果为10了
造成返回结果总是1,是受作用域的影响。早期JavaScript没有块级作用域的概念,需要借助闭包模拟块级作用域。
代码实现
ES6中原生支持块级作用域,let
代码实现
好多回答。。不知道你是不是已经看懂了
首先理解下作用域的概念,简单的说,在{}内产生的变量只在{}内有效, 如果有嵌套{ A { B } }的情况,内部域B可以得到外部域A中的变量,外部域A不能得到内部域B中的变量。
然后说下在这个例子里面为什么每个函数都返回10,i的这种声明方式等价于
此时i的域是在外部的, 所以for里的作用域可以得到i这个值并且每次拿到的都是同一个i, 所以在function里的i拿到的也是同一个i, 注意
这个操作只是一个赋值操作,function只是创建了但是并没有执行。
最后说下闭包,"正常情况下一个函数在运行结束后会销毁函数内部的所有变量来释放内存,当函数内部有变量为了保持被外部方法的调用而没有自动销毁的这个现象就是闭包",在这个例子里面正常来说执行完return result后就会销毁,但是如果result被赋值给外部的某个变量,比如说
这个时候a这个数组就可以执行来返回i这个变量, i这个变量为了保持外部a这个变量的调用而使得createFunctions这个函数没有销毁而被保存,这个就是闭包,上面是我对闭包的理解。
这里用的到是函数闭包的问题,可以看看阮一峰的博客