只摘了一些"至理名言",还有我觉得有用的东西.
实质问题
“函数仍持有对某作用域的引用,该引用叫闭包.”
说明闭包指的是一种引用关系.
“只要使用了回调函数,实际上就是在使用闭包.”
回调函数肯定是在别处调用的,在其他词法作用域调用,其又保留了对原作用域的引用使原作用域存活.
闭包不一定只维持原作用域存活,实际上闭包函数依赖的结构所在的作用域都将维持存活.
函数必须是在本身的词法作用域外执行,并且其依赖的结构通过闭包被发现而非作用域链查找,才能形成闭包.
循环与闭包问题
for(let i = 10; i > 0; i--){
setTimeout(function cl() {
console.log(i);
}, i * 1000);
}
期望每秒输出1-10,结果每秒输出0.
设置定时器时的确为1000,2000,3000ms输出,即每秒输出,但setTimeout使回调函数被放于异步执行,只能取到循环后i的最终值.
那么要如何破解困局? 问题的本质是什么?为什么i不断覆盖?
因为for内只有一个词法作用域,导致i被不断覆盖,cl被不断声明.如果我们每轮循环都创建新的词法作用域,在每个作用域都声明cl,存储那轮循环的i,就能达到目的.
一定要把那一轮的i存在作用域内,否则每个作用块的cl依旧只能取到for作用域的最终i.
如下:
for (let i = 10; i > 0; i--){
(function() {
var j = i;
setTimeout(function cl() {
console.log(j);
},j * 1000);
})();
}
此处用具名立即执行函数表达式的函数作用域来存储每轮循环的结构,可以达到目的.