什么是闭包?
JavaScript 闭包(Closure)概念 允许嵌套函数访问在父函数的作用域中定义的变量,即使父函数的执行已经完成。简而言之,你可以使用闭包使全局变量成为 local 或 private。
JavaScript 闭包基本上是函数及其词法环境的组合。这允许内部函数访问外部函数范围。每次在函数创建时创建函数时,都会创建一个 Closure。
在开始学习闭包(Closure)的概念之前,你需要了解词法作用域、嵌套函数和返回函数的概念。
词法范围
在 JavaScript 中,词法范围是一个概念,其中变量的范围是在代码编译时根据代码的结构确定的。例如,嵌套函数可以访问父函数范围内的变量,这称为词法作用域。
嵌套函数
您可以在函数内部定义函数,内部函数称为嵌套函数。让我们通过下面的示例来学习它。
例在下面的示例中,我们在 outer() 函数中定义了 inner() 函数。此外,inner() 函数在 outer() 函数内部执行。
当我们执行 outer() 函数时,它还会执行 inner() 函数,一个嵌套函数。
输出
The inner function is executed!
返回函数
当任何函数返回函数而不是值或变量时,它称为返回函数。让我们看看下面的示例。
例在下面的代码中,outer() 函数返回函数定义,并将其存储在 'func' 变量中。之后,我们使用 'func' 变量来调用存储在其中的函数。
输出
The inner function is executed!
The inner function is executed!
现在,您了解了学习闭包所需的先决条件。
JavaScript 闭包的定义有点混乱,但我们会一步一步地学习闭包的概念,这样你就会明白。
反困境( A Counter Dilemma)
例如,您创建计数器来递增和递减变量。如下所示,您需要对 counter 使用全局变量。
例在下面的示例中,全局变量 'cnt' 初始化为 100。每当执行 decrement() 函数时,它都会将 'cnt' 变量的值减少 1。
输出
The value of the cnt is: 98
The value of the cnt is: 97
上面的代码完美地用作递减计数器,但问题是 'cnt' 变量可以在代码中的任何地方访问,并且代码的任何部分都可以在不执行 decrement() 函数的情况下更改它。
在这里,JavaScript 闭包出现了。
示例:JavaScript 闭包
在下面的示例中,counter() 函数返回 decrement() 函数。'cnt' 变量在 counter() 函数内定义,而不是在全局范围内定义。
decrement() 函数将 'cnt' 的值减少 1 并打印在输出中。
'func' 变量包含 decrement() 函数表达式。每当执行 func() 时,它都会调用 decrement() 函数。
输出
The value of the cnt is: 98
The value of the cnt is: 97
现在,让我们再次记住 closure 的定义。它表示嵌套函数可以从外部函数的作用域访问变量,即使外部函数的执行已完成。
在这里,counter() 函数的执行结束了。不过,您可以调用 decrement() 函数并使用更新的值访问 'cnt' 变量。
让我们看另一个 closure 的例子。
例在下面的示例中,name() 函数返回 getFullName() 函数。getFullName() 函数将字符串与在外部函数的作用域中定义的 'name' 变量合并。
输出
闭包(Closure)的好处
以下是 JavaScript 中闭包的一些好处 -
- 封装 − 闭包允许开发人员隐藏或封装数据。它使数据私有化,并且无法从全局范围访问。因此,您可以只公开所需的变量和函数,并隐藏代码的其他内部详细信息。
- 保留状态 − 即使外部函数的执行已完成,函数也会记住其词法范围。因此,开发人员可以像在上面示例中维护计数器的状态一样维护状态。
- 提高内存效率 − 闭包允许您有效地管理内存,因为您只能保留对必要变量的访问权限,而不需要全局定义变量。