概念
什么是闭包?
一个函数和它周围状态的引用捆绑在一起的组合
听到这句话可能有的小伙伴有点难以理解,那么你也可以理解成
函数嵌套函数,内部函数就是闭包
闭包应用
在了解到闭包的概念后,我们带着闭包的概念来对闭包进行探讨
function f() {
let a = 10
}
console.log(a)
我们在js中设置这样的一串代码,设置一个函数,在函数内部定义一个变量a,我们想通过外部来访问函数的内部变量a,我们会发现控制台给我们报错了
这是为什么呢?那是因为函数存在作用域,在函数作用域内,内部可以读取外部变量,但外部不可以读取内部变量, 所以我们在全局中调用函数内部的变量的时候就肯定会报错,那我们要如何解决这个问题呢?所以我们就要引入闭包来解决这个问题,我们把上面的代码进行改装一下
function Out() {
let a = 10
return function () {
console.log(a)
}
}
var foo = Out()
foo()
我们执行这串代码我们就发现了,我们可以访问到函数的内部变量a了,因为我们在out函数内部返回一个函数,在返回的函数中我们去调用局变量a,由于返回的函数中没有变量a,所以它会通过作用域链,在我们定义函数的地方向上级进行查找,此时再将我们调用out函数赋值给foo,那么此时foo其实就是等于out函数return出来的函数,即
foo = function () {
console.log(a)
}
然后我们再去调用foo函数,即调用eturn出来的函数,这样我们就可以拿到函数内部的变量a了,通过这个例子我们就发现了通过闭包,外部可以访问到函数内部的变量了.
在这里可能就有小伙伴就会问了,当返回的函数内部没有a时,为什么他会向在定义的时候查找,而不是调用的时候查找呢?
这个时候我们就要回到闭包的概念上:一个函数和它周围的状态引用绑定在一起的组合
我们理解这句话的时候就会发现,返回的函数它周围的状态引用就是out中定义的a绑定在一起,所以当返回函数内部没有a的时候,他会向在定义的时候向上级查找。
在这串代码的演示中,可能就有小伙伴还会有一个疑问,当一个函数调用完成后,其内部的变量不是会被销毁吗,为什么调用完out函数后,内部函数还能访问到变量a呢?
在这里我们就要引入闭包重要的一个特征了,即:内部函数没有执行完成,外部函数的变量就不会进行销毁
因为闭包这条重要的特征所以我们就能够访问到变量a。
虽然说闭包的特性给予了我们很多的方便,但他也有一个存在的缺点,假如我们经常去调用一个闭包函数,那么外部函数的变量就不会销毁,那么他就会一直储存在我们的内存中,不能被释放出来,那么就会造成内存泄漏。
通过上面的对闭包的理解过后我们思考一道这样的题
function f() {
let a = 10
f1()
}
let a = 20
function f1() {
console.log(a)
}
f()
请问图中的最终输出的结果是多少?
我们拿到这道题后我们先进行分析,我们调用f函数,首先是我们先进入f函数,我们发现f函数里面定义了一个变量a,然后调用了f1函数,那么我们就可以发现这个其实就是函数嵌套函数,这就是一个闭包函数,那我们继续分析,我们进入到f1函数中我们发现在内部调用了console.log的方法,那么现在我们就要去找变量a的值是多少,由于闭包的概念:一个函数和它周围的状态引用绑定在一起的组合,所以我们就要在f1定义的地方去进行查找,然后再向上级查找,我们发现f1上级就是全局作用域,此时a就等于20,所以在我们的最终结果就是20。
在我们的实际开放中我们为了防止变量的污染,我们在封装组件的时候经常会应用闭包来解决很多的问题。