一直对闭包这个概念模糊不清,今天捣鼓半天,大致理通了。
闭包是什么?
有权访问另外一个函数作用域中的变量的函数。
一般来讲,作用域是由函数创建的(这里我们只讨论函数作用域,不涉及ES6之后的块级作用域)。每个函数的作用域都是封闭的,外部是无法访问函数作用域中的变量。
那有没有办法可以从外部访问到函数内部的变量呢
答案是有的,通过嵌套函数的方式,见下面的示例。
function change(){
var a = 1
function plus(){
a++
console.log(a)
}
return plus
}
var final = change()
final() //2
final() //3
final() //4
在该例中,我们得增加点知识点:
- 函数的作用域
- 变量的生命周期
plus函数作用域内没有变量a,依据作用域链,找到父作用域中的变量a,当执行final()时,a++,a=2。再执行final()时,结果依然+1。
这里有点困惑,变量的生命周期起始于函数执行时,终止于函数执行完毕,为什么这里面函数中的变量a未被回收,数值一直递增。
原因在于变量a被函数plus引用,final()间接引用着变量a。导致变量a未被内存回收。
闭包最大的用处在于:暴露局部变量,保持变量在内存中不被回收。
再来看些经典的闭包题来理解下思路
for(var i = 1; i< 10; i++){
function a(){
console.log(i)
}
}
a() //10
为什么得到10,很简单。for循环中是函数表达式,当循环结束后,执行a(),其中的i不存在按作用域链找到上一级的i并引用,结果为10。
怎么让其按我们设想的0,1,2...输出呢?
也很简单,每次循环执行一次函数,传参,var a = i ,运用立即执行函数,见下
for(var i = 1; i< 10; i++){
!function a(a){
console.log(a)
}(i)
}
如果纠结0~9,和输出来为什么是10,可以参考下for循环的执行次序