菜鸟笔记
提升您的技术认知

js闭包详解,看完必会

先来一段闭包的代码

function outerFunction() {
  
  var outerVariable = "I am defined in outerFunction";

  function innerFunction() {
  
    console.log(outerVariable);
  }

  return innerFunction;
}

var inner = outerFunction();
inner(); // 输出 "I am defined in outerFunction"

在这个示例中,outerFunction 是一个包含一个内部函数innerFunction的函数。在 outerFunction 中,我们定义了一个局部变量 outerVariable,并在 innerFunction 中访问了它。

innerFunctionouterFunction 中被定义,然后被返回。当我们调用 outerFunction 时,它返回 innerFunction 的引用,并赋值给变量 inner

当我们调用 inner 时,它实际上是在调用 innerFunction,并访问了 outerVariable。尽管 outerFunction 已经执行完毕并返回了,但是由于 innerFunction 在其词法环境中仍然保留对 outerVariable 的引用,所以 outerVariable 仍然可以被访问。

这种能力是通过闭包实现的:innerFunction 捕获并保存了对 outerVariable 的引用,从而使得 outerVariable 可以在 outerFunction 执行完毕后仍然被访问。

一,什么是闭包?

闭包是指有权访问另一个函数作用域中变量的函数,即使这个函数已经执行完毕并返回。可以通过返回一个函数或者把函数作为参数传递给另一个函数来创建闭包。闭包可以捕获外部函数的变量,并且这些变量可以在闭包内被访问和操作,这使得闭包可以在许多场景下被使用,例如封装变量、实现模块化、缓存数据等。

二、闭包的实现原理

在 JavaScript 中,函数可以访问它定义时所处的作用域中的变量。当一个函数被定义时,它会创建一个新的作用域,并将自己包含在其中。这个新的作用域称为“函数作用域”或“词法作用域”。当函数中引用一个变量时,JavaScript 引擎首先在函数作用域中查找该变量。如果在函数作用域中找不到该变量,它将继续在外部作用域中查找,直到找到该变量为止。

当一个函数嵌套在另一个函数中时,内部函数可以访问外部函数的变量。如果内部函数在外部函数返回后仍然存在,并且仍然可以访问该变量,则该变量将继续存在于内存中。这是因为内部函数仍然保留对其原始作用域的引用,从而防止垃圾回收器将该变量清除出内存。

三、闭包的作用

闭包在 JavaScript 中有很多重要的用途,例如:

1.封装变量

闭包可以将变量封装在一个私有作用域中,从而防止它们被外部访问和修改。这是实现面向对象编程中“私有变量”的一种方式。

2.模拟私有方法

使用闭包可以模拟类中的私有方法。私有方法是指只能在类内部访问的方法,这样可以隐藏一些实现细节,提高代码的可维护性和安全性。

3.记忆上下文

闭包可以用于记忆函数的上下文。例如,在 JavaScript 中,setTimeout 函数会创建一个新的作用域,导致函数的 this 值发生改变。使用闭包可以将函数的上下文保存下来,并在 setTimeout 回调函数中使用。

4.防止全局命名空间的污染

闭包可以防止全局命名空间的污染。在 JavaScript 中,所有的变量都属于全局作用域,如果不小心定义了一个全局变量,可能会与其他变量发生冲突。使用闭包可以将变量封装在私有作用域中,从而避

四,闭包的优缺点

1.优点

  • 可以在函数内部创建私有变量和函数,避免变量污染全局作用域。
  • 使得函数内部变量的值得以保留,可以访问到外部函数的变量,从而扩展了函数的作用范围和灵活性。
  • 可以用于实现类似于面向对象编程中的私有变量和方法。
  • 可以帮助提高代码的模块化和可复用性。

2.缺点

  • 内存占用:由于闭包会保留对外部环境的引用,所以在不需要时不释放内存,可能导致内存泄漏
  • 性能问题:由于闭包涉及到访问外部变量,因此会带来一定的性能损失。
  • 可读性差:使用闭包会增加代码的复杂性,不易理解和维护。
  • 安全问题:如果闭包中的变量被误用或篡改,可能导致安全问题。