【个人理解】闭包

220 阅读3分钟

前言

最近在看书打基础,本文是在群中分享的自己对闭包的一个理解,在这整理成文,给其他对闭包不了解或者一知半解的童鞋参考,如果你已经懂了,还请节约你的时间按下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中并没有声明变量abconsole.log(a, b)在执行的时候,会先从[1]中找ab,找不到的情况下,会接着从[2][3]中去找。

小结

函数中的变量取值,会通过不断冒泡,向外查找。

函数作用域

再来看一张图:

这是我理解的函数bar执行时候的作用域。区域window中为全局变量,这个例子包括我们声明的变量b,区域foo中包括变量a。在执行函数bar()时,到了console.log(a, b),会按照bar->foo->window的顺序去查找变量。这跟我们平时理解的从[1]冒泡到[2]然后是[3],有所区别,但本质上是一样的。

小结

内层函数将会包括函数自己声明的变量,以及外层函数声明的变量。

我理解的闭包

闭包的产生在于将foo中声明的函数barreturn了出去,这个时候,函数foo的返回值是bar的引用,通过var baz = bar(),将函数bar给暴露到了全局作用域下。

在执行baz()时,实际上是在调用函数‘bar’,执行过程中的作用域依旧跟上图一样,这样就能够在全局作用域下访问到foo中的变a

小结

通过返回内层函数的引用,保留对外层函数变量的引用,使得在外层函数的外部,依旧能够访问外层函数中的变量。

总结

这是我对闭包的一个大致理解,没有表达清楚或者有疑问的地方,可以在评论区留言。

想要了解闭包,需要对下面的一些知识点有一定的了解:

  • 值传递与引用传递
  • 函数参数的隐式赋值
  • 函数作用域

并且还需要一定的积累,才能养成一种类似于直觉上的理解。如果看了我的文章让你对闭包的认识有了改进,点点屏幕上的👍呗。