什么是闭包?
闭包是可以访问其定义的“外部"范围的函数,因此,即使闭包函数终止,它也可以访问外部作用域中的值。
例子:
function takeOne(){
let i = 0;
return function incrementFunction(){
return i++;
}
}
上面的代码表示一个函数返回另一个函数。但是,调用takeOne并获取后incrementFunctioon,即使已经终止incrementFunction,takeOne也会记住局部变量takeOne。
使用闭包的好处
闭包的第一个好处就是将局部变量保留在范围内。由于JavaScript函数是一等公民,因此开发人员经常会遇到名称冲突,这将倒是意外输出。使用闭包可以帮助将该范围内的名称空间保留为私有变量。可以在过去的jQuery代码中看到很多东西,其中定义了click方法。
$(function () {
var selection = [];
$('.something').click(function(){ //此闭包可以访问外部变量selections
selections.push('something') //获取外部函数选择
})
})
第二个好处是更多在一般情况下使用,它在异步环境中很有用。
例如,遍历数组的值:
for(var i = 0; i < 3; i++){
setTimeout (()=> console.log(i),3000);
}
该程序的输出是什么?
打印3 三遍。 由于setTimeout是异步的,所以在循环结束时,外部作用域i也已经更改为3,并且setTimeout在循环期间对后续调用将触发回调3次打印。
如何解决?
解决这个问题其实有很多方法,包括使用ES6语法的let,而不是var在块级别定义范围并解决问题。但是,如果希望不使用任何ES6功能的情况下解决问题,则使用闭包才是最优选择
function printSomething(i){
setTimeout(()=>console.log(i),3000)
}
for(var i = 0; i < 3;i++){
printSomething(i);
}
通过仅在外部创建另一个外部函数setTimeout,就可以定义一个闭包,该i值即使printSomething终止也会被保留,然后回调将打印0,1,2到控制台。
这就是JavaScript闭包强大的功能所在,可以使用闭包在异步环境中保留外部变量的范围。
闭包的一般用例在于在异步环境中求解计算。