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)

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

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

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

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