闭包是什么?它的作用与注意事项

210 阅读3分钟

一说到闭包,很多人选择视而不见,认为它用的不多又难以理解,但是躲得和尚躲不得寺,想成为一个优秀的前端工程师,闭包是必须掌握的知识点。在小黄书《你不知道的JavaScript》中有这样一句话:非常重要但又难以掌握,近乎神话的概念一一闭包。这篇文章我将带大家了解什么是闭包以及它的优缺点,其中我会举出许多例子方便大家理解。

先大致介绍一下闭包,帮助后面理解

闭包(Closure)作为JavaScript中的重要概念,它是一种强大且灵活的机制,正确理解和使用它可以写出更加模块化、高效和安全的代码。它的核心在于它能够“封闭”或“捕获”外部作用域的变量,即便外部函数已经执行完毕,这些变量依然可以被内部函数访问。

如果有不了解作用域的可以去我主页中找到文章《JavaScript的作用域和预编译》,里面有对作用域的详解。

下面我们来看一段代码,清晰地展示了闭包:

function foo(){
   var a=2;
   function bar(){
        console.log(a);
        }
        return bar;
 }
 var baz=foo();
 baz();   // 2

由输出结果不难看出bar()可以正常执行,这时我们需要在编译与运行上分析一波,全局运行foo(),当return bar;执行完后,通常会期待foo()的整个内部作用域都被销毁,因为在引擎中会有垃圾回收器用来释放不再使用的内存空间。由于当最后一句代码执行完时,会认为foo()的内容不会再被使用,所以很自然地会考虑将其进行回收。而闭包的神奇之处就在于它会阻止这件事情的发生

原本a 为 2 这个值会被回收,但在这里它将a的值留下了,因为foo()本身这个方法包含的bar()方法中还需要用到a这个值。bar()依然持有对该作用域的引用,而这个引用就叫做闭包

我们可以把闭包抽象成“背包”:这个闭包就相当于foo()的背包,foo()做完它的事情将它的背包留下了,让它的手下bar()可以接着使用它背包中的工具。

闭包的作用

  • 在添加事件监听器或设置定时器时,闭包可以帮助我们保持正确的上下文环境。举个例子:
function func(message){
   setTimeout( function timer(){
      console.log( message );
      },500);
      }
      func("Hello,world");

func执行500毫秒后,它的内部作用域不会完全消失,timer函数依然保有func作用域的闭包,可以使用它的message

  • 通过闭包可以创建私有变量,防止外部直接修改内部状态。(最常用)
  • 可以用来创建具有特定状态或配置的函数实例。(函数工厂)
  • 在ES6之前,JavaScript没有块级作用域的概念,闭包可以用来模仿这一特性。

注意事项

  • 闭包可能会引发内存泄漏。

内存泄漏:程序未能释放不再使用的已分配内存空间。

  • 降低性能

频繁创建闭包或者闭包链过长可能会影响性能,特别是在大量使用时要注意优化。

结语

其实代码中到处都是闭包的存在,我们需要识别它然后熟练地使用它。闭包作为JavaScript学习者的必修课,当我们真正掌握它时,也说明我们在前端之路又向前迈了一大步。

参考文献:《你不知道的JavaScript》