【闭包】JavaScript中的作用域闭包详解

85 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

前言

闭包,一个用了这么多年还在慢慢了解的概念。虽然有了大量的JavaScript的使用经验,但是好像又从未真正去理解闭包的概念。

总是感觉闭包是个很隐蔽的东西,它的工作原理也是一个很神奇的东西。

闭包,并不是JavaScript中的一个需要去学习的语法或者模式才能使用的东西,它无处不在,只要你能识别它即可。

识别闭包

😎 当函数可以记住并访问所在的词法作用域时,就会产生闭包,就算函数是在当前词法作用域之外去执行。

function foo(){
    var a = 1;
    
    function bar(){
        console.log(a);
    }
    
    bar();
}

foo();

image.png

  • 此时在 bar函数中输出的 a 就会是 foo函数中定义的值

😵 上面这段代码展示出来的结果是闭包嘛?是,但也不是

  • bar函数中对 a 的引用方法只是词法作用域里面的查找规则,这些规则只是闭包中的一部分而已。
  • bar函数则具有一个涵盖 foo函数作用域的闭包,也可以理解为 bar函数被封闭在 foo函数的作用域里面。

从上面的代码中,我们并不能直接观察闭包是如何工作的,我们只能看出它属于词法作用域,而闭包则隐藏在代码之中而已。

function foo(){
    var a = 1;
    
    function bar(){
        console.log(a);
    }
    
    return bar;
}

var fun = foo();
fun();

image.png

🧐 这个输出的 1 就是闭包的效果了。

  • bar函数的词法作用域能够访问 foo函数的内部作用域。
  • 我们把 bar函数当做一个值去传递,并把 bar函数当作返回值。

😕 我们通常对于函数执行的理解中,会觉得 foo函数在执行之后,会把内部作用域都销毁掉,因为引擎的垃圾回收器会用来释放不再使用的内存空间。

由于 foo函数的内容看上去不会再使用了,所以会考虑将其回收掉。

闭包的神奇之处就是可以阻止回收这件事情的发生。由于bar函数的使用,内部作用域依然会存在,因为不会被回收。

bar函数持有对该作用域的引用,这个引用就被称为闭包

总结

通过上面的例子你可能会有点迷糊,可能还需要更多的时间去理解。只要在项目开发过程中,慢慢熟悉闭包的原理,就会发现其实闭包并不复杂,它出现在你的逻辑代码的各个地方。