面试官:JavaScript执行机制中的闭包?

前言

JavaScript 中的闭包指的是一个函数以及其捆绑的周边环境状态的引用的组合。闭包可以让开发者从内部函数访问外部函数的作用域,即使外部函数已经执行完毕

今天我们通过JavaScript执行机制来聊聊闭包

正文

首先来分析这段代码的执行机制,这段代码我们主要了解作用域链,以及函数的外部作用域outer

outer是根据词法作用域规则生成的

function bar() {console.log(myName);
}
function foo() {var myName = 'Tom'bar()
}var myName = 'Jerry'
foo()

在上述代码中,执行 foo 函数时,在 bar 函数内部打印 myName 时,会查找变量 myName

由于 bar 函数内部没有定义 myName ,它会沿着作用域链向上查找。首先在 foo 函数的作用域中查找,foo 函数中定义了 myName'Tom' ,但是 bar 函数调用时,它无法直接访问 foo 函数作用域内的 myName

接着继续向上查找,在全局作用域中找到了定义的 myName'Jerry' ,所以最终打印的是全局作用域中的 myName ,即 'Jerry'

我们来画一下这个的执行流程

image.png

  • 调用栈中创建全局上下文执行对象(变量、词法环境)里面有bar=x001指向堆里面(非原始数据类型存放地)foo myName
  • myName最开始是undefined,全局预编译结束,全局执行,myName=Jerry 调用foo
  • 对foo进行预编译,创建AO对象(foo的执行上下文对象)有变量词法环境,myName=undefined,foo里面代码开始执行,
  • myName=Tom,foo变量环境中还有一个outer指针,值指向全局上下文执行对象,为什么指向全局?
  • outer指向谁取决于foo函数所在的词法作用域在哪里(foo声明在哪里),foo在全局作用域中,所以outer指向全局上下文执行对象
  • 这个指向过程就是作用域链,bar开始调用,创建bar执行上下文,入栈,有变量、词法环境,
  • 变量环境中没有声明东西,但是有outer指针,指向全局上下文对象。
  • 然后开始找myName,自己bar中没有找到,然后顺着outer往全局找,找到了jerry因此打印jerry

这里我们还没具体讲解闭包

接下来我们分析这段代码

function foo() {function bar() {var age = 18console.log(myName);}var myName = 'Tom'return bar
}
var myName = 'jerry'
var fn = foo()
fn()

在上述代码中,执行 fn() 时,在 bar 函数内部打印 myName ,首先在 bar 函数内部查找 myName 变量,未找到。

然后沿着作用域链向上查找,在 foo 函数的作用域中找到了定义的 myName'Tom'

而全局作用域中定义的 myName'jerry' ,但由于作用域链的查找顺序,优先使用了 foo 函数作用域中的 myName ,所以最终打印的是 'Tom'

这我们同样分析一下预编译过程

image.png

这里我们就要引出闭包了,当bar执行完了,就得被销户,然后就是foo了,可是这里就出现了一个问题,foo返回了一个方法barbarouter指向的foo,但是foo就被销毁了,可是在全局调用了bar,bar是需要使用到foo里的参数的,于是就还是销毁了foo,但是留下了bar需要的参数,以及他的outer,形成了小书包,这就是闭包

image.png

闭包有许多的好处:

  1. 实现数据私有化和封装
    通过闭包,可以将一些变量和函数隐藏在内部函数中,外部无法直接访问和修改,从而实现了一定程度的封装和数据保护。
  2. 保持函数执行的上下文和状态
    闭包能够让函数记住其创建时的环境状态,即使外部函数已经执行完毕,内部函数仍然可以访问和操作这些状态信息。这对于实现需要保持状态的功能非常有用,比如计数器、缓存等。
  3. 模拟私有方法
    在 JavaScript 中没有真正的私有方法,但可以利用闭包来模拟私有方法,只在特定的函数内部可访问和操作。
  4. 函数柯里化和偏函数应用
    闭包有助于实现函数柯里化和偏函数应用,使函数的参数传递更加灵活和可定制。
  5. 模块模式
    可以使用闭包创建模块,模块中的变量和方法只在模块内部可访问,对外只暴露必要的接口。

那么让我们分析一下这段代码

function add() {let count = 0;function fn() {count++return count;}return fn;
}
var res = add();
console.log(res());
console.log(res());
console.log(res());

add函数的调用是不依赖全局变量的,封装函数 实现累加

add 函数返回了内部函数 fn

当执行 var res = add(); 时,res 接收到了 fn 函数,并且 fn 函数形成了一个闭包,能够访问到 add 函数中的 count 变量。

第一次执行 console.log(res()); 时,count 自增为 1 并返回,所以打印 1

第二次执行 console.log(res()); 时,count 再次自增为 2 并返回,所以打印 2

第三次执行 console.log(res()); 时,count 继续自增为 3 并返回,所以打印 3

总结

本文讲解了JavaScript的执行机制和JavaScript执行机制中的闭包,相信看到这里的你一定会有收获的!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/356027.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

太牛了!AI换脸数字人,限制解除,免费用!

哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 今天给大家安利一款美图公司出品的神器,功能限制完全解除,可以免费使用AI换脸数字人、AI提词器、AI脚本、AI抠图、AI清除、AI封面等超多超实用功能,…

Freertos-----任务之间的消息传递(使用消息队列信号量方法)

这次来分享任务之间的数据传递的方法,方法有很多种,我展示2种,让大家对freertos有更深刻的印象 目录 消息队列 信号量 消息队列 首先直接打开普中的例程,然后在里面加上ADC的驱动代码,先初始化外设先,我…

【ARMv8/ARMv9 硬件加速系列 1 -- SVE | NEON | SIMD | VFP | MVE | MPE 基础介绍】

文章目录 ARM 扩展功能介绍VFP (Vector Floating Point)SIMD (Single Instruction, Multiple Data)NEONSVE (Scalable Vector Extension)SME (Scalable Matrix Extension)CME (Compute Matrix Engine)MVE (M-profile Vector Extension)MPE (Media Processing Engine)总结 ARM 扩…

【刷力扣】23. 合并 K 个升序链表(dummy节点技巧 + 分治思维 + 优先队列)

目录 一、合并升序链表问题二、题目:[21. 合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/description/)1、掌握dummy节点的技巧 三、题目:[23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/descri…

ASP.NET Core 6.0 启动方式

启动方式 Visualstudio 2022启动 IIS Express IIS Express 是一个专为开发人员优化的轻型独立版本的 IIS。 借助 IIS Express,可以轻松地使用最新版本的 IIS 开发和测试网站。 控制台版面 直接在浏览器输入监听的地址,监听的是 http://localhost:5137 脚本启动 dotnet run…

Dockerfile 自定义镜像

大家好 , 今天我要和大家分享一个现代软件开发中不可或缺的工具 - Docker . 在这个快速发展的技术时代 , 我们经常面临着应用部署的复杂性、环境差异以及不同操作系统之间的兼容性问题 . 这些问题不仅消耗大量时间 , 还可能导致项目延期和成本增加 . Docker 的出现解决了我们在…

成都晨持绪:现在的抖音网店怎么做更快起店

在当今社交媒体的浪潮中,抖音已经成为一个不可忽视的电商平台。对于想要快速起步的抖音网店来说,掌握一些关键策略至关重要。 首要的是定位清晰。你的网店需要有一个鲜明的主题,这可以是某一特定领域的产品,如美妆、服饰或是手工艺…

银河麒麟V10安装docker和docker-compose

1. 说明 系统镜像使用的是Kylin-Server-V10-SP3-2403-Release-20240426-x86_64.iso如果是在VMware中安装这个系统,需选择Ubuntu,如果选Centos会有问题。 尝试使用在线方式安装docker,报了很多错误,比较麻烦,建议使用离…

分享由AI制定一个商城网站的开发计划及推荐的开发语言

商城网站开发计划 一、项目概述 本商城网站开发计划旨在创建一个功能齐全、用户友好的在线购物平台,为顾客提供商品浏览、搜索、购物车管理、订单跟踪、在线支付等服务。商城将支持多种商品分类,包括但不限于电子产品、家居用品、服饰鞋帽等。 二、开…

数据结构【二叉树】

前言 我们在前面学习了使用数组来实现二叉树,但是数组实现二叉树仅适用于完全二叉树(非完全二叉树会有空间浪费),所以我们本章讲解的是链式二叉树,但由于学习二叉树的操作需要有一颗树,才能学习相关的基本…

【Web APIs】DOM 文档对象模型 ④ ( querySelector 函数 | querySelectorAll 函数 | NodeList 对象 )

文章目录 一、querySelector 函数1、querySelector 函数简介2、完整代码示例 二、querySelectorAll 函数1、querySelectorAll 函数简介2、完整代码示例 三、NodeList 对象1、NodeList 对象简介2、完整代码示例 本博客相关参考文档 : WebAPIs 参考文档 : https://developer.moz…

Java中将文件转换为Base64编码的字节码

在Java中,将文件转换为Base64编码的字节码通常涉及以下步骤: 读取文件内容到字节数组。使用java.util.Base64类对字节数组进行编码。 下面是一个简单的Java示例代码,演示如何实现这个过程: import java.io.File; import java.io…

【HarmonyOS NEXT】鸿蒙 如何在包含web组件的页面 让默认焦点有效

页面包含web组件Button组件等,把页面的默认焦点放到Button组件上,不起效果。 因为web组件默认会在组件加载完成后获取焦点; 可以在web的网页加载完成时onPageEnd回调中,将设置默认获焦的组件通过focusControl.requestFocus方法主…

gitlab升级16.11.3-ee

背景 这是事后一段时间补充记录的博客。 升级目的:修补漏洞CVE-2024-4835 未经认证的威胁攻击者能够利用该漏洞在跨站脚本 (XSS) 攻击中,轻松接管受害者账户。 gitlab版本为14.6.2-ee升级至16.11.3-ee 思路 翻阅文档找升级方法及升级版本路径。使用…

切割游戏介绍

简介 上大学时,在学校实验室里玩过一个貌似使用VC写的小游戏,一个小球在界面上四处游荡,玩家使用鼠标切割背景,将背景切割剩余到一定的百分比后,就胜利了,后边的背景图会全部展示出来。 使用qt的qml技术&a…

Linux_文件IO

目录 一、库函数进行文件操作 1、fopen/fclose 2、fwrite 3、追加方式-“a” 4、fread 5、三个默认文件流 二、系统函数进行文件操作 1、open/close 2、write 3、追加方式-“O_APPEND” 4、read 5、struct file结构体 6、文件描述符 6.1 struct file的引用…

Pyqt QCustomPlot 简介、安装与实用代码示例(一)

目录 简介安装实用代码示例带有填充的简单衰减正弦函数及其红色的指数包络线具有数据点的 sinc 函数、相应的误差条和 2--sigma 置信带几种散点样式的演示展示 QCustomPlot 在设计绘图方面的多功能性 结语 所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转…

数学-奇异值

有点名词党 奇异值的计算通常涉及矩阵的奇异值分解Singular Value Decomposition, SVD。奇异值分解是将一个矩形矩阵 ( A ) 分解为三个矩阵的乘积: [ A U ΣVT] 其中: - ( U ) 是一个 ( m m ) 的正交矩阵,它的列向量是 ( A AT) 的特征向…

课程标准包括哪些内容?

老师们常常会思考:课程标准究竟包含哪些要素?课程标准不仅仅是一系列冷冰冰的条条框框,而是活生生的指导原则,引领教学实践,激发学生的潜能。 课程标准,简而言之,是对学习成果的期望和要求的明确…

Starlink全系卫星详细介绍,波段频谱、激光星间链路技术、数据传输速率等等

Starlink全系卫星详细介绍,波段频谱、激光星间链路技术、数据传输速率等等。 Starlink是SpaceX公司开发的一个低轨道(LEO)卫星网络系统,旨在为全球用户提供高速宽带互联网服务。截至2024年6月,Starlink已经发射并运行…