彻底理解js中的闭包

2023-11-19

闭包是js的一个难点也是它的一个特色,是我们必须掌握的js高级特性,那么什么是闭包呢?它又有什么用呢?

我们都知道,js的作用域分两种,全局和局部,基于我们所熟悉的作用域链相关知识,我们知道在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得当前包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的,那么我们想在一个函数内部也有限权访问另一个函数内部的变量该怎么办呢?闭包就是用来解决这一需求的,闭包的本质就是在一个函数内部创建另一个函数。

 

我们首先知道闭包有3个特性:

①函数嵌套函数

②函数内部可以引用函数外部的参数和变量

③参数和变量不会被垃圾回收机制回收

 

本文我们以闭包两种的主要形式来学习

 

①函数作为返回值

在这段代码中,a()中的返回值是一个匿名函数,这个函数在a()作用域内部,所以它可以获取a()作用域下变量name的值,将这个值作为返回值赋给全局作用域下的变量b,实现了在全局变量下获取到局部变量中的变量的值

再来看一个闭包的经典例子

一般情况下,在函数fn执行完后,就应该连同它里面的变量一同被销毁,但是在这个例子中,匿名函数作为fn的返回值被赋值给了fn1,这时候相当于fn1=function(){var n = 0 ... },并且匿名函数内部引用着fn里的变量num,所以变量num无法被销毁,而变量n是每次被调用时新创建的,所以每次fn1执行完后它就把属于自己的变量连同自己一起销毁,于是乎最后就剩下孤零零的num,于是这里就产生了内存消耗的问题

 

再来看一个经典例子-定时器与闭包

写一个for循环,让它按顺序打印出当前循环次数

按照预期它应该依次输出1 2 3 4 5,而结果它输出了五次5,这是为什么呢?原来由于js是单线程的,所以在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候,for循环已经结束,i的值也已经编程5,所以打印出来五个5,那么我们为了实现预期结果应该怎么改这段代码呢?(ps:如果把for循环里面的var变成let,也能实现预期结果)

 

引入闭包来保存变量i,将setTimeout放入立即执行函数中,将for循环中的循环值i作为参数传递,100毫秒后同时打印出1 2 3 4 5

那如果我们想实现每隔100毫秒分别依次输出数字,又该怎么改呢?

在这段代码中,相当于同时启动3个定时器,i*100是为4个定时器分别设置了不同的时间,同时启动,但是执行时间不同,每个定时器间隔都是100毫秒,实现了每隔100毫秒就执行一次打印的效果。

 

②闭包作为参数传递

在这段代码中,函数fn1作为参数传入立即执行函数中,在执行到fn2(30)的时候,30作为参数传入fn1中,这时候if(x>num)中的num取的并不是立即执行函数中的num,而是取创建函数的作用域中的num这里函数创建的作用域是全局作用域下,所以num取的是全局作用域中的值15,即30>15,打印30

 

最后总结一下闭包的好处与坏处

好处

①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突

②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)

③匿名自执行函数可以减少内存消耗

坏处

①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;

②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

彻底理解js中的闭包 的相关文章

  • 如何使用 lodash、underscore 或 bluebird 同步迭代数组 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有一个数组 其中每个索引处包含文件名 我想下载这些文件一次一个 同步 我知道关于 Async 模块 但我想知道是否有任何功能Lodash
  • 如何查询和过滤 Firebase 实时数据库 [重复]

    这个问题在这里已经有答案了 我想从数据库中获取所有人员 其中名字和姓氏由用户输入给出 到目前为止 这是我的代码 admin database ref persons orderByChild Firstname equalTo firstN
  • 在 JavaScript 中计算不包括周末和节假日的天数

    我正在尝试编写一个代码 其中将计算总天数 不包括周末和自定义假期 我通过 stackoverflow 和 adobe 论坛进行搜索以找到解决方案 并提供了以下代码 如果公共假期恰逢工作日 周六至周三 则不计算在内 我的问题是 如果公共假期落
  • React 无法识别 DOM 元素上的 `isActive` 属性 - styled-components

    我有以下内容svg我传递道具的组件 import React from react export default props gt
  • codePointAt 和 charCodeAt 之间的区别

    有什么区别String prototype codePointAt and String prototype charCodeAt 在 JavaScript 中 A codePointAt 65 A charCodeAt 65 从 MDN
  • 如何对像 Excel Pivot 这样两个键必须匹配的数组求和?

    我尝试对 Datum 和 Material 必须匹配的所有 Menge 和 Fehler 值求和 结果应类似于 Excel 数据透视表 到目前为止 这是我的代码 但我不知道如何添加也必须匹配的第二个键 Material 我希望你能理解我试图
  • 为什么人们将自己的自定义/用户函数添加到 jQuery 对象中? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我见过人们将自己的自定义 用户功能添加到jQuery目的 例如 myUserFunc function regular JS code 你为什么
  • 当key未知时如何获取js对象中的属性值

    我有一个对象数组 a 81 25 p 81 25 81 26 p 81 26 我想循环遍历数组并获取值p在每个元素中 for var key in a console log a key outputs 81 25 Object How d
  • 如何使用 JavaScript 压缩文件?

    有没有办法使用 JavaScript 来压缩文件 例如 在雅虎邮件中 当您选择下载电子邮件中的所有附件时 它会被压缩并下载到单个 zip 文件中 JavaScript 能够做到这一点吗 如果是这样 请提供一个编码示例 我发现这个图书馆叫js
  • 如何使用 javascript 将我的域名字母大写?

    假设我的域名是www hello com 如何使用 jQuery JavaScript 使浏览器的 URL 栏看起来像 www HELLO com 您无法更改浏览器地址栏中显示的内容 这是一项基本的安全功能 您可以使您的域名全部大写 并将页
  • es6-module 默认导出导入为未定义

    我不确定我在这里缺少什么 我正在使用 jspm 和 es6 module loader 开发一个项目 我有一个模块定义如下 import hooks from hooks import api from api import tools f
  • 数据表 - 从 AJAX 源过滤数据

    我有一个数据表 正在从 api 获取数据 现在我的状态是活动的 非活动的 如果标志是活动的 那么我需要在数据表中显示 否则我不应该显示过期的 这是我的fiddle https jsfiddle net lakshmipriya001 qLp
  • 分配函数后如何删除 onmouseout 事件?

    我有一个问题 我正在为 onmouseout 事件分配一个函数 但运行该事件后 我需要将其删除 将非常感谢您的帮助 这取决于你的代码 如果你用 d3 这样做 那么你可以说 在 onmouseout 事件函数中 element on mous
  • 如何在 getStaticPaths 内添加 params 值数组

    我有一个页面 其结构如下 read slug number 我想要得到slug每个对应的值number in the getStaticPaths这是代码 export async function getStaticPaths const
  • JS - 如何将图像对象变成灰度并显示它

    基本上 当单击按钮时 它会告诉移动设备转到相机 一旦相机拍照 它就会给我图像数据 它被称为数据 URL 吗 这是我处理它的代码 var imagesrc data image jpeg base64 imageData var myimag
  • 如何加载Jquery Tiny滚动条

    所以我想自定义一个滚动条 我发现了一个很小的滚动条 这是一个jquery插件 http baijs nl tinyscrollbar http baijs nl tinyscrollbar 问题是 无论如何我都无法让它工作 我将 Jquer
  • 数组长度未定义[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我试图按如
  • 调用一个从 AngularJS 表达式本地计算值的函数是不是很糟糕?

    我读了关于使用范围的一些 AngularJS 陷阱的文章 http thenittygritty co angularjs pitfalls using scopes 并且它指出您不应在表达式中使用函数 并且我知道每次框架认为需要时都可能会
  • 如何将函数导入到Vue组件中?

    我正在尝试将单个函数导入到我的 Vue 组件中 我为我的函数创建了一个单独的 js 文件 randomId js exports randomId gt My function 在我的 Vue 组件中 我导入了 Random js let
  • 如何向 SvelteKit/Vite 应用添加版本号?

    我正在尝试在我的 SvelteKit 应用程序中创建一个系统 它会在某个页面上向您显示有关当前应用程序版本的信息 最好是 Git 提交哈希和描述 我尝试使用Vite的定义功能 https vitejs dev config define在构

随机推荐

  • CISCN2018-WP

    MISC 验证码 用token登录 输入好验证码就可以得到flag Picture 图片隐写 一下就想到binwalk或者winhex打开试试 binwalk打开无果 将这段数据ctrl shift c复制出来 用下面python脚本生成z
  • HTML标签及浮动

  • 7.块设备驱动的I/O请求处理(2)

    不适用请求队列 使用请求队列对于一个机械磁盘设备而言的确有助于提高系统的性能 但是对于RAMDISK ZRAM Compressed RAM Block Device 等完全可真正随机访问的设备而言 无法从高级的请求队列逻辑中获益 对于这些
  • 稳定性相关大纲

    稳定性建设的几个维度 个人渣记录仅为自己搜索用的博客 CSDN博客 道法术器 稳定性相关 代码 产品灰度能力 降级百分比能力 动态diamond doom测试 单元测试 稳定性改造 高资源占用优化 方法 架构上改造降流量 例如心跳 内部逻辑
  • 真正的阅读者,是不需要荐书的

    From http www luanxiang org blog archives 2136 html 早上一个朋友在朋友圈里跟我说 上次你推荐的 信息简史 和 知识的边界 两本书 我觉得很不错 这条消息让我比较差异 首先我并没有 推荐 过
  • 数据集分割

    步骤 1 确定训练集和测试集是否同分布 常用方法 1 留出法 实现 直接将数据集拆分为互斥的训练集 验证集和测试集 划分比例 训练集 验证集 测试集 7 1 5 1 5 注意事项 单次使用留出法会导致模型不稳定 保证三种数据集中样本比例的相
  • Linux 下使用 C++ 实现的 Web 文件服务器

    项目地址 Github https github com shangguanyongshi WebFileServer 在学习完成 TCP IP 网络编程 和 Linux高性能服务器编程 后 阅读了一些Web服务器的相关代码 自动动手使用
  • code style

    最近一直在看java convention和google c style 因为老板要提高代码质量 我们小公司一个 因为客户说我们的代码质量太烂了 于是开始搞代码质量 先从静态 代码质量开始 于是就研究起来code style 但是 我发现
  • Pthread 并发编程(三)——深入理解线程取消机制

    基本介绍 线程取消机制是 pthread 给我们提供的一种用于取消线程执行的一种机制 这种机制是在线程内部实现的 仅仅能够在共享内存的多线程程序当中使用 基本使用 include
  • 【ARM】程序快速定位segmentation fault core dumped错误

    1 应用场景 ARM开发过程中经常进程运行着出现段错误 这时候单纯靠加日志打log效率太低 使用gdb的话 由于APP进程太多 生成的core的文件特别大 而且gdb在arm板子也不好单步调试 不太友好还是pass掉 目前使用段错误捕捉SI
  • Python3爬虫——用Xpath提取网页信息

    Python3爬虫 用Xpath提取网页信息 前言 本笔记用于记录整理requests库的一些基本知识 内容会根据博主自己的认知作增添或压缩 水平有限 如有错误请不吝赐教 本文需要读者初步了解HTML有关节点的相关知识 文章目录 Pytho
  • Python技能练习!值得你看的28道常见题型汇总!(附答案解析)

    今天给大家分享30道Python练习题 建议大家先独立思考一下解题思路 再查看答案 文末有惊喜 1 已知一个字符串为 hello world yoyo 如何得到一个队列 hello world yoyo 使用 split 函数 分割字符串
  • C#多线程Lock锁定的使用例子(多线程线程同步)

    这个例子是一个模拟多个人在多台提款机上同时提取一个账户的款的情况 在存取的过程中 可能 A线程取了100 而B线程那边还看见账户上没少掉那100快 所以导致数据不统一 赋值出现问题 下面代码则可以测试出加上Lock锁定 与 不加的区别 先上
  • 学会这几个简单的bat代码,轻松在朋友面前装一波13

    这个标题是干什么用的 最近看晚上某些人耍cmd耍的十分开心 还自称为 黑客 着实比较搞笑 他们那些花里胡哨的东西在外行看来十分nb 但只要略懂一些 就会发现他们的那些十分搞笑和滑稽 今天这里分享几个类似的方法 让你在不懂行的朋友面前秀一波
  • xuexila作文 lxml etree xpath如何同时选择多种标签tag

    以学习啦为例 说明如何选择一个大范围标签下面的两个及以上种类标签tag 例如 div p 1 p h2 2 h2 p 3 p div 只有同时可以选择p h2 内容1 2 3的顺序才不会乱 from lxml import etree im
  • 数据库表结构设计

    做一个项目 必然是少不了数据库设计的 在学习阶段 基本都是单表 然而在实际开发过程中 一对多 多对多的表处处都是 简单整理一下 一对多 多对多表如何设计整理一下思路 数据库实体间有三种对应关系 一对一 一对多 多对多 一对多 一的主键放在多
  • Sublime中自动代码提示插件Anaconda插件下载及设置

    Sublime中自动代码提示插件Anaconda插件下载及设置 一 代码提示功能插件 Anaconda 通过package Control 进行插件下载 按住ctr shift p会弹出对话框 没果没有的话 需要进行package Cont
  • Python可迭代类

    Python可迭代类 iter 和 next python中我们常常会用到for循环结构 for 元素 in 元素来源 for循环后面的元素来源实际上就是一个可以迭代的对象 for in 语句其实做了两件事 第一件事是获取一个可迭代对象 即
  • QT5.14解决控制台打印中文乱码的问题

    如上图 在控制台打印的中文显示乱码 解决方法如下 第一 在main函数中加入 pragma execution character set utf 8 第二 将所有字符串包含中文 用QStringLiteral修饰 综上解决中文乱码问题
  • 彻底理解js中的闭包

    闭包是js的一个难点也是它的一个特色 是我们必须掌握的js高级特性 那么什么是闭包呢 它又有什么用呢 我们都知道 js的作用域分两种 全局和局部 基于我们所熟悉的作用域链相关知识 我们知道在js作用域环境中访问变量的权利是由内向外的 内部作