前言
最近在看书打基础,本文是在群中分享的自己对闭包的一个理解,在这整理成文,给其他对闭包不了解或者一知半解的童鞋参考,如果你已经懂了,还请节约你的时间按下ctrl+w/cmd+w,也可提出你的看法,欢迎探讨。
MDN对闭包的解释
函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在 JavaScript 中,每当函数被创建,就会在函数生成时生成闭包。——MDN
我的理解
变量查找
先来看看代码:
// window
var b = 'this is b in window' // [3]
function foo() {
var a = 'this is a in foo'; // [2]
function bar() {
console.log(a, b); // [1]
}
return bar;
}
var baz = foo();
baz(); // this is a in foo this is b in window
当我们调用baz()时,执行的是[1]中的代码,在函数bar中并没有声明变量a和b,console.log(a, b)在执行的时候,会先从[1]中找a和b,找不到的情况下,会接着从[2]和[3]中去找。
小结
函数中的变量取值,会通过不断冒泡,向外查找。
函数作用域
再来看一张图:
这是我理解的函数bar执行时候的作用域。区域window中为全局变量,这个例子包括我们声明的变量b,区域foo中包括变量a。在执行函数bar()时,到了console.log(a, b),会按照bar->foo->window的顺序去查找变量。这跟我们平时理解的从[1]冒泡到[2]然后是[3],有所区别,但本质上是一样的。
小结
内层函数将会包括函数自己声明的变量,以及外层函数声明的变量。
我理解的闭包
闭包的产生在于将foo中声明的函数bar给return了出去,这个时候,函数foo的返回值是bar的引用,通过var baz = bar(),将函数bar给暴露到了全局作用域下。
在执行baz()时,实际上是在调用函数‘bar’,执行过程中的作用域依旧跟上图一样,这样就能够在全局作用域下访问到foo中的变a。
小结
通过返回内层函数的引用,保留对外层函数变量的引用,使得在外层函数的外部,依旧能够访问外层函数中的变量。
总结
这是我对闭包的一个大致理解,没有表达清楚或者有疑问的地方,可以在评论区留言。
想要了解闭包,需要对下面的一些知识点有一定的了解:
- 值传递与引用传递
- 函数参数的隐式赋值
- 函数作用域
并且还需要一定的积累,才能养成一种类似于直觉上的理解。如果看了我的文章让你对闭包的认识有了改进,点点屏幕上的👍呗。