面试官: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.mzph.cn/bicheng/31596.shtml

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

相关文章

详细解读“找不到mfc140u.dll无法继续执行代码”问题

当你打开某个软件或者运行游戏,系统提示mfc140u.dll丢失,此时这个软件或者游戏根本无法运行。其实,mfc140u.dll是动态库文件,它是VS2010编译的软件所产生的,如果电脑运行程序时提示缺少mfc140u.dll文件,程序…

PHP 8.4有哪些新功能值得关注

属性钩子(Property Hooks) 允许开发者为每个属性定义自己的get和set钩子,以在属性访问前后添加自定义逻辑。属性钩子通过__get()和__set()方法实现,类似于其他编程语言(如Kotlin、C#和Swift)中的属性访问器…

C++标准库:STL以及输入输出库,IO库,Cmath库,时间库,智能指针库与并发库等简介

标准库 C 标准库是 C 编程语言的核心部分,提供了丰富的功能和组件,包括容器、算法、迭代器、函数对象、智能指针、输入输出操作等。C 标准库主要包括以下几个组件: STL(Standard Template Library):STL 是…

复分析——第6章—— Γ 函数和 ζ 函数(E.M. Stein R. Shakarchi)

第6章 Γ函数和Ζ函数(The Gamma and Zeta Functions) 毫不夸张地说,Γ函数和Ζ函数是数学中最重要的非初等函数之一。Γ函数在自然界中无处不在。它出现在大量计算中,并以分析中出现的大量恒等式为特征。对此的部分解释可能在于Γ函数的基本结构特性&…

游戏心理学Day21

玩家情绪与暴力攻击 情绪 情绪的分类 情绪是一种经常波动的东西,我们既体验过骄傲激动和开心,也体验过羞怯内疚和沮丧。我们的感受高度依赖于情境。研究者区分出至少三种途径来考察作为一种相对固定的人格特征的情绪,即为情感性&#xff0…

lock_wait_timeout

lock_wait_timeout 是 MySQL 中的一个重要参数,它用于控制当一个 MySQL 会话在等待锁时的等待时间。以下是关于 lock_wait_timeout 的详细解释: 定义与功能 定义:lock_wait_timeout 是一个会话或线程级别的参数,用于指定 MySQL …

python20 函数的定及调用

函数的定及调用 函数是将一段实现功能的完整代码,使用函数名称进行封装,通过函数名称进行调用。以此达到一次编写,多次调用的目的 用 def 关键字来声明 函数 格式: def 函数名(参数列表):函数体[:return 返回值是可选的&#xff0…

小白如何如何理解滑动窗口最大值问题python

文章目录 题目描述思路什么时候弹出元素什么时候加入元素 代码示例和解释 题目描述 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 举例: 输…

命令行脚本批量转换工具说明

O N C E , ONCE, ONCE,EACH,$0都是NimbleText的关键字 O N C E : 任何 在 ′ ONCE:任何在 ONCE:任何在′ONCE’关键字之后的文本将只输出一次,不管有多少行,到’$EACH’关键字或者到文件末尾为止。 E A C…

《沃趣 分手后霸道少爷宠爆我》盛大开机典礼

南京五聚文化传媒有限公司自豪地宣布,引人入胜的2024年度短剧巨作——《沃趣 分手后霸道少爷宠爆我》——今日正式开拍!在星辰下的华丽舞台上,我们汇集了业界的精英力量,准备讲述一个关于爱、错位与重生的故事。 典礼精彩亮点 1.…

0621熟悉项目

1、store:全局状态管理器。共享给各组件的数据。 2、首页组件组成:layout组件下的index为入口。左侧菜单栏SidebarNew(大概意思是遍历数组生成菜单),右侧菜单栏app-mai(主体内容) main-tags-view&#xff0…

数据治理工程师CDGA备考心得、时间安排、题库资源

1.写在前面 之前做一些数据质量控制、元数据、主数据相关工作,一直忙于工作,没有去往考证的方面想,去年年底心血来潮就决定考一考,证多不压身嘛(也有部分学生向我咨询),资源在文章结尾&#xff…

逻辑学中的蕴涵式:SQL开发者必备知识

逻辑学中的蕴涵式:SQL开发者必备知识 在逻辑学中,蕴涵式(Implication)是一种常见的逻辑关系,用于描述两个命题之间的条件关系。在SQL开发中,理解蕴涵式的概念和真值规则对编写复杂查询语句非常有帮助。本文…

onnx转openvino模型(2022版本和2024版本)

网上很多方法都是用openvino自带的mo_onnx.py来转的,但个人下载的2022和2024版都没见到这些文件。所以使用不了 (1)2022版openvino:python需要安装对应版本的openvino库(以2022.3.0为例) pip install openvino2022.3…

软件测试——稳定性测试:adb Monkey

Monkey 1. Monkey1.1 Monkey 是什么1.2 Monkey 测试场景1.3 Monkey 特点1.4 Monkey 在哪里1.5 测试准备事项1.6 Monkey 参数列表 2. 基本命令3. 常用参数4. 事件类型5. 调试参数6. 日志管理7. 日志错误定位8. Monkey测试可以发现的问题 1. Monkey 1.1 Monkey 是什么 Monkey是一…

MySQL笔记——事务

事务 **控制事务****并发事务问题**事务隔离级别 学习黑马MySQL课程,记录笔记,用于复习。 控制事务 方式一: #查看和设置事务提交方式 select autocommit ; set autocommit 0 ; #提交事务 commmit; #回滚事务 rollback;方式二:…

electron自定义标题栏的最大化,最小化,关闭窗口

渲染组件代码&#xff1a; <template><div class"window-btn"><i class"minimize" click"minimize"><img src"../assets/img/最小化.svg" alt"最小化" /></i><i v-if"!isMaximized&…

react 0至1 案例

/*** 导航 Tab 的渲染和操作** 1. 渲染导航 Tab 和高亮* 2. 评论列表排序* 最热 > 喜欢数量降序* 最新 > 创建时间降序* 1.点击记录当前type* 2.通过记录type和当前list中的type 匹配*/ import ./App.scss import avatar from ./images/bozai.png import {useState} …

【408考点之数据结构】队列:定义、特点、基本操作与应用

队列&#xff1a;定义、特点、基本操作与应用 队列的定义 队列&#xff08;Queue&#xff09;是一种特殊的线性表&#xff0c;仅允许在一端进行插入操作&#xff08;称为队尾&#xff0c;Rear&#xff09;&#xff0c;在另一端进行删除操作&#xff08;称为队头&#xff0c;F…

Springboot开发之 Excel 处理工具(二)-- Easyexcel

一、Easyexcel 简介 EasyExcel是一个基于Java的Excel处理工具库&#xff0c;它的核心设计理念是快速、简洁&#xff0c;并且能够有效解决处理大文件时的内存溢出问题。使用EasyExcel&#xff0c;开发者可以在几乎不需要考虑性能和内存消耗的情况下&#xff0c;轻松实现Excel文…