接上文 https://blog.csdn.net/u012312705/article/details/81749777 (有关闭包的经典问题)
想要处理不想要发生的闭包,最简单的方式就是let啦
以setTimeout形成的闭包为例
for(let i = 0 ; i < 10 ; i++){
setTimeout(()=>{
console.log(i); // 0 - 9
console.log(this.i); // undefined
});
}
如果是用的var i,那么很明显会输出20个10,但是用let 就会输出0 - 9和undefined了,
这是因为let会形成一个块级作用域(作用死域),且不会存在变量提升,而setTimeout的this永远绑定window,所以this里是找不到作为全局变量的i的。
块级作用域类似于c语言以及java里的作用域的行使方式一样,会保留i的状态,所以十次调用setTimeout都会展示i的变化
那么若是想要实现let,就是要用各种神奇的方式,把i的状态全都保存下来噢
第二种方式
try-catch
for(var i = 0 ; i < 10 ; i++){
try {
throw i;
} catch (e) {
setTimeout(()=>{
console.log(e)
})
}
}
在这里try-catch伪造的块级作用域存在于catch里,其中e是一个有着类似于块级作用域变量的特性的独立变量,他不是i,所以能够保留下i的状态的变化。
第三种方式
自执行函数,函数
for(var i = 0 ; i < 10 ; i++){
(function(i){
setTimeout(()=>{
console.log(i);
});
})(i);
}
for(var i = 0 ; i < 10 ; i++){
function a(i){
setTimeout(()=>{
console.log(i);
})
}
a(i);
}
用传递参数的方式保留i的状态
第四种方式
map,forEach
来自ES6的对数组的方法
for(var i = 0 ; i < 10 ; i++){
[i].map((i)=>{
setTimeout(()=>{
console.log(i);
})
});
[i].forEach((i) => {
setTimeout(()=>{
console.log(i);
})
});
}
这里是用数组保存了i的状态
不知道还有没有其他办法,但是这四种,实在是足够花式了,一般来说一个let就可以搞定啦~,当然不要忘记let的无法被变量提升的效果噢