闭包 = 词法环境 + 函数,一个函数记住并能访问其外部词法环境
这个函数可以调用其所在词法环境下的变量,例如
function goEnvironment(firstWord:string){
const words = firstWord + ",";
return function(secondWords){
const wholeWords = words + secondWords;
console.log(wholeWords);
}
}
const getHelloWords = goEnvironment("Hello");
const getHeyWords = goEnvironment("Hey");
// getHelloWords & getHeyWords
getHelloWords('worlds');// Hello,worlds
getHeyWords('bibao');// Hey,bibao我们看到goEnvironment函数内部的匿名函数,可以直接调用goEnvironment 包含的词法环境中的变量 words,这就是闭包。
可以用来解决循环中的异步问题
例如使用 var 在循环中使用
for(var i = 0;i<5;i++){
setTimeout(function(){
console.log(i);//总是输出5
},i*100);
}我们知道,异步函数会在同步执行完成之后再按照异步队列顺序执行,所以再同步循环结束之后才会执行,此时我们的词法环境中所存储的 i 就是 5,所以一直输出 5
解决方法:
- 使用 let 创建 i
for(let i = 0;i<5;i++){
setTimeout(function(){
console.log(i);//总是输出5
},i*100);
}let 创建的作用域是块级作用域
- 使用 iife
for(var i = 0;i<5;i++){
(function(index){
setTimeout(function(){
console.log(index);//总是输出5
},i*100);
})(i);
}原理是将 i 作为立即执行函数参数传进每一个循环中的立即执行函数的词法环境中
内存泄漏问题
因为闭包创建后,如果里面的函数内部调用了外部词法环境的变量,但是这个函数又不使用,则垃圾回收机制不会将闭包的词法环境删除,导致内存泄漏