JavaScript 闭包的魔力:清晰易懂的指南
JavaScript 中的闭包是什么?
将闭合想象成您下课后随身携带的背包。背包里有你在课堂上学到的所有笔记和材料。即使课程结束后,您仍然可以在需要时使用背包中的所有物品。类似地,闭包允许函数保留对其外部作用域的变量和参数的访问,即使在外部函数完成运行并且这些变量在该函数外部不再可访问之后也是如此。
上面的解释是描述闭包的典型方式,但是对于刚接触 JavaScript 的人来说它适合初学者吗?并不真地。当我第一次遇到它时,我也觉得很困惑。这就是为什么我写这篇文章是为了让闭包尽可能简单,让任何人都能理解。我们将首先介绍基础知识,然后再深入探讨该主题。
理解 JavaScript 中的作用域
要理解什么是闭包,我们必须简要了解一下 JavaScript 中的作用域。范围是指代码不同部分中变量和函数的可访问性。它决定了我们可以在程序中访问某些变量或函数的位置。
作用域有两种主要类型:全局作用域和局部作用域。在全局作用域中声明的变量存在于任何函数或块之外,从而使它们可以在整个代码中访问。相反,在局部范围内(例如在函数或块内)声明的变量只能在该特定函数或块内访问。下面的代码说明了这一解释。
// GLOBAL SCOPE let myName = "John Doe"; function globalScope() { console.log(myName); } globalScope(); //Output John Doe console.log(myName); // Accessible here as well // LOCAL SCOPE function localScope() { let age = 30; console.log(age); } localScope(); //Output 30 console.log(age); //Output age is not defined (Not Accessible)
然而,JavaScript 使用了一个称为词法作用域的概念,这对于理解闭包的工作原理至关重要。词法作用域意味着变量的可访问性由编写代码时的结构决定。简单来说,这就像在说:“如果在函数内声明变量,则只有该函数及其中的任何内容都可以访问该变量。”{https://javascript.info/closure}。
词法范围和执行上下文
为了更清楚地理解这一点,让我们看看 JavaScript 在幕后是如何工作的。 JavaScript 使用称为执行上下文的东西,它就像一个保存正在运行的代码的容器。它跟踪变量、函数以及当前正在运行的代码部分。当脚本启动时,将创建全局执行上下文 (GEC)。需要注意的是,程序中只有一个全局执行上下文。
上图代表了程序开始时的全局执行上下文。它由两个阶段组成:创建(或内存)阶段和执行(或代码)阶段。在创建阶段,变量和函数存储在内存中——变量被初始化为未定义,函数被完全存储。在执行阶段,JavaScript 逐行运行代码,为变量赋值并执行函数。
现在我们了解了 JavaScript 如何处理执行上下文和词法作用域,我们可以看到它如何直接与闭包联系起来。
闭包如何工作:一个例子
当内部函数保留对其外部函数作用域中的变量的访问权限时,即使外部函数已完成执行,也会创建 JavaScript 中的闭包。这是可能的,因为内部函数保留了定义它的词法环境,允许它“记住”并使用外部作用域中的变量。
// GLOBAL SCOPE let myName = "John Doe"; function globalScope() { console.log(myName); } globalScope(); //Output John Doe console.log(myName); // Accessible here as well // LOCAL SCOPE function localScope() { let age = 30; console.log(age); } localScope(); //Output 30 console.log(age); //Output age is not defined (Not Accessible)
这是有关上述代码如何工作的指南。每当我们调用一个函数时,JavaScript 引擎都会创建一个特定于该函数的函数执行上下文 (FEC),该函数执行上下文是在全局执行上下文 (GEC) 内创建的。与 GEC 不同,一个程序中可以有多个 FEC。每个 FEC 都会经历自己的创建和执行阶段,并拥有自己的变量和词法环境。词法环境使函数能够从其外部作用域访问变量。
当outerFunction被调用时,会创建一个新的FEC,在outerFunction内部,我们定义innerFunction,由于词法作用域,它可以访问outerVariable。在outerFunction返回后,outerFunction的执行上下文将从调用堆栈中删除,但innerFunction由于闭包而保留对outerVariable的访问。因此,当我们稍后调用closureExample()时,即使outerFunction已经完成,它仍然可以记录outerVariable。
闭包的实际应用
让我们看一下以下示例:
Let’s look at the example below: function outerFunction() { let outerVariable = 'I am John Doe'; return function innerFunction() { console.log(outerVariable); }; } const closureExample = outerFunction(); closureExample(); // Outputs: "I am John Doe"
你认为这段代码的输出会是什么?你们中的许多人可能猜到了 5,但这真的是正确的输出吗?事实上,不,原因如下。函数 y() 引用变量 a,而不是其初始值。当 z() 被调用时,由于返回内部函数之前进行了更新,它会记录 a 的当前值,即 50。让我们探讨另一个例子:
function x(){ let a = 5 function y(){ console.log(a) } a = 50 return y; } let z = x(); console.log(z) z();
代码展示了闭包的威力。即使在最里面的函数 z() 中,它仍然可以从其父作用域访问变量。如果我们检查浏览器并检查 Sources 选项卡,我们可以看到 x 和 y 上都形成了闭包,这允许 z() 从其父上下文访问 a 和 b。
使用闭包的优点
闭包在 JavaScript 中提供了多种优势,特别是在编写更灵活、模块化和可维护的代码时。以下是一些主要优点:
1。回调函数: 闭包在处理异步编程时非常强大,例如回调、事件监听器和 Promise。即使在外部函数完成后,它们也允许回调函数保持对外部函数变量的访问。
// GLOBAL SCOPE let myName = "John Doe"; function globalScope() { console.log(myName); } globalScope(); //Output John Doe console.log(myName); // Accessible here as well // LOCAL SCOPE function localScope() { let age = 30; console.log(age); } localScope(); //Output 30 console.log(age); //Output age is not defined (Not Accessible)
2。模块化和可维护性: 闭包允许开发人员编写更小、可重用的代码块,从而鼓励模块化。由于闭包可以在函数调用之间保留变量,因此减少了对重复逻辑的需求并提高了可维护性。
3。避免全局变量: 闭包有助于减少对全局变量的需求,从而避免潜在的命名冲突并保持全局命名空间干净。通过使用闭包,您可以将数据存储在函数范围内而不是全局。
结论
闭包是 JavaScript 中一个强大的概念,它允许函数记住和访问其外部作用域中的变量,甚至在函数执行之后也是如此,从而扩展了函数的功能。此功能在创建更加模块化、灵活且高效的代码方面发挥着重要作用,特别是在处理异步任务、回调和事件侦听器时。虽然闭包一开始可能看起来很复杂,但掌握它们将使您能够编写更复杂和优化的 JavaScript。当您继续练习时,您将发现闭包如何帮助编写更干净、更易于维护的应用程序。不断尝试,很快闭包将成为你的 JavaScript 工具箱的自然组成部分。
以上是JavaScript 闭包的魔力:清晰易懂的指南的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。
