【JS 田井中律】掌握 JavaScript 闭包和记忆化

JavaScript Closures and Memoization
闭包

JavaScript 闭包是现代 Web 开发中广泛使用的一个重要概念。简单来说,闭包允许函数记住和访问它的词法环境( lexical environment),即使该函数是在其原始范围之外执行的。这个概念起初听起来可能很复杂,但它是创建模块化、高效和安全代码的基本工具。在这篇文章中,我们将深入探讨闭包并提供其用法的真实示例。
What?Why?什么是闭包
闭包 --> 函数
闭包是一个函数,可以访问其外部(封闭)词法环境中的变量。换句话说,它可以访问其父函数中定义的变量和参数,即使该函数已完成执行。这之所以成为可能,是因为 JavaScript 处理范围的方式。
在 JavaScript 中,每个函数都会创建一个新的词法作用域(lexical scope)。这意味着在函数内声明的任何变量只能在该函数的范围内访问。但是,当一个函数定义在另一个函数内部时,内部函数可以访问外部函数的作用域,包括其中定义的任何变量或参数。这就是使闭包成为可能的原因。
How?闭包示例
让我们看一个简单的闭包示例。在此示例中,我们有一个名为 outerFunction
的函数,它定义了一个名为 outerVariable
的变量。该函数还返回另一个函数,我们称之为 innerFunction
。 innerFunction
可以访问 outerVariable
,即使它是在其自身范围之外定义的。
在此示例中,我们调用 outerFunction
并将结果分配给名为 closure
的变量。 closure
现在是可以访问 outerVariable
的函数,即使 outerFunction
已完成执行。当我们调用 closure()
时,它会记录“Hello, world!”到控制台。
When?Where?闭包的真实场景
出于各种原因,闭包在现代 Web 开发中被广泛使用。以下是闭包可能有用的一些真实场景:
1)创建私有变量和方法 Private Variables and Methods
闭包可用于创建私有变量和方法。在 JavaScript 中,没有内置的方法来创建私有变量和方法。但是,通过使用闭包,我们可以创建只能在特定函数范围内访问的变量和方法。
让我们看一个例子:(是不是想到了ReactJS 的自定义钩子)
在上面的示例中,我们有一个名为 counter
的函数,它创建了三个内部函数: increment
、 decrement
和 getCount
。这些内部函数可以访问在 counter
范围内定义的 count
变量,并且它们可以根据需要修改或返回它。结果是一个具有私有变量和方法的“计数器”对象。
2)事件处理程序 Event Handlers
闭包可用于创建可以访问特定数据的事件处理程序。这在处理异步代码时特别有用,在异步代码中变量可能会发生不可预测的变化。
这是一个例子:
jiy3)记忆化 Memoization
记忆化是一种用于通过缓存昂贵函数调用的结果并在相同输入再次出现时返回缓存结果来优化函数性能的技术。
下面是一个使用闭包的记忆示例:
在这个例子中,我们有一个名为 memoize
的函数,它接受函数 func
作为参数。 memoize
返回一个可以访问 cache
对象的新函数。当使用某些参数调用记忆函数时,它会检查结果是否已被缓存。如果有,则返回缓存的结果。如果没有,它将使用提供的参数调用原始函数,缓存结果并返回它。
小结
闭包是在 JavaScript 中创建模块化、高效和安全代码的基本工具。它们允许函数记住和访问它们的词法环境,即使它们是在它们的原始范围之外执行的。闭包可用于多种用途,包括创建私有变量和方法、创建事件处理程序和缓存。通过了解闭包以及如何有效地使用它们,开发人员可以编写出更好、更高效、更易于维护和调试的代码。