闭包和原型链是JavaScript这门语言的核心,到目前为止,我对闭包也只是一个肤浅的认识。就先试着写一点吧…
起初我只知道闭包大概就两个作用,一个就是模仿块级作用域,另外一个就是js实现变量的私有。然后对其中的细节全然不知,直到我看到了这样一个问题
for(var i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i)
},i*1000)
}
惯性思维脱口而出,每秒依次输出1,2,3,4,5…
其实,并不,它每秒依次输出6…
为什么会出现这种情况呢?大概有两个原因
1.js的执行机制导致,js会自动把耗时的回调放到同步队列后面执行(改天咱们再来谈谈js的执行机制)
2.众所周知,js在es6出来前是没有块级作用域的,使得循环的5个函数共享同一个作用域
好,咱们整理一下,就是定时器回调函数被放到了循环之后执行,循环终止i为6。因为作用域共享,循环得到的结果依次被覆盖,最后就当然全部是6啦。
怎么解决这个问题呢?
当然就是靠闭包!
for(var i = 1; i <= 5; i++){
(function(j){
setTimeout(function timer(){
console.log(j);
},j*1000)
})(i)
}
因为js的作用域为函数级作用域,那就先创建一个自执行函数,执行循环的时候依次给自执行函数内传入i,用一个变量接收,这个变量作用范围仅在这个函数内部,循环创建的5个函数互不影响,因而在循环执行完毕后到达对应时间点输出结果就得到意想的结果!是不是很棒!
捋一捋思路,其实这也便是其他语言块级作用域的优点,js在没有es6前块级作用域就是如上那样用创建函数来模拟的,当有了es6之后,整个世界似乎变得更加有趣了
for(let i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i);
},i*1000)
}
换成let
声明一切又变得那样亲切…