当函数能够记住并访问所在的词法做用域时,就产生了闭包,即便函数是在当前词法做用域以外执行。前端
下面的代码的运行结果和代码语意上表达的不相符,咱们但愿它可以每隔一秒输出一次,每次输出对应的数字,即第一秒后输出1,第二秒后输出2......
而这段代码的运行结果是,第一秒后输出6,第二秒后输出6......
请解释缘由而且提出修改方案。(包含要点,函数做用域,块做用域,闭包,let)es6
for (var i = 1; i <= 5; i++) { setTimeout(function timer() { console.log(i); }, i*1000); }
var i,实际上声明了一个全局变量segmentfault
延迟函数timer必然是在循环结束后才开始执行,循环结束后,i=6前端框架
循环中确实定义了多个延迟函数timer,延迟函数在setTimeout的内部被回调,根据闭包概念,timer在其声明以外的地方被调用,timer可以记住并访问其声明位置的词法做用域,存在闭包闭包
实际上timer所记住的词法做用域就是全局做用域,因此引用输出的i都是6框架
只要能保证每次循环都可以建立新的做用域,在新做用域中保存当前i的值便可函数
因此任何能够建立新做用域的方法均可以达到效果,具体可参考这里,经过分析这段代码的进化历程,或许可以加深您对JavaScript的做用域的理解code
常见的作法有ip
利用具名当即执行函数,每次循环都建立新做用域作用域
for (var i = 1; i <= 5; i++) { (function scope(j) { setTimeout(function timer() { console.log(j); }, i * 1000); })(i); }
利用es6 let建立块做用域
for (var i = 1; i <= 5; i++) { { let j = i; setTimeout(function timer() { console.log(j); }, i * 1000); } }
根据闭包的概念,只要有回调就会有闭包......
记住这个例子,还怕被问闭包?
最近写了三篇,参考书籍主要是《你不知道的JavaScript(上卷)》,看完这三篇能够说就至关于看了半本书了,^_^前端框架层出不穷,不反对使用框架,但必定要有头头能驾驭的了它。试想,作前端的人那么多,若是冰河世纪来临,存活下来的仍是那些会写框架的人,那些只懂框架使用的人就危险了我快毕业了,但内心慌慌的,因此若是您刚入门,建议仍是扎扎实实地学基础,其实JS基础远比您想象的要复杂,千万别觉得本身看了W3C School就以为本身Ok了,反正我是要再努力下,争取看得懂牛人的代码哈下篇见......