【JavaScript闭包】JavaScript何为闭包,浅谈闭包的形成和意义

news2024/11/28 7:44:36

谈到js,必然逃不了闭包。
闭包到底是啥呢?我查了不少资料,解释真的是各种各样,千奇百怪,令人困惑。
我们先来看看一下各种解释

  • 红宝石书:闭包指的是那些引用了另一个函数作用域中变量的函数。
  • mdn : 闭包(closure)是一个函数以及其捆绑的周边环境状态的引用的组合
  • 其它 : 闭包就是指有权访问另一个函数作用域中的变量的函数
    这可以说是我们最常见的几种说法。
    第一和第三种说法,我们把句子整合一下,就是说闭包是个函数

然后再来说说我们常看见的闭包

function func() {
    const a = 1;
    return () => a;
}
const oFunc = func();

我相信大多数人一开始见到的闭包都是这样
一个内部函数引用了外部函数作用域的变量,然后这个函数被保存函数外部。

作用域

首先说一句,闭包一定跟作用域有关。
作用域有块级作用域,函数作用域,全局作用域。
函数之所以能访问到外部作用域中的变量和函数,正是因为有作用域链的存在。

作用域是当前的执行上下文,值 和表达式在其中“可见”或可被访问。如果一个变量 或表达式不在当前的作用域中,那么它是不可用的。作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反过来则不行。

一句话内层作用域能访问外层作用域的东西。

这跟一个东西有关。叫作用域链。

作用域链[[scope]]其实就是包含指针的列表,可以看作是一个数组,每个指针都指向一个变量对象。

这里的变量对象又牵扯到另一个东西叫做执行上下文。

执行上下文

执行上下文是动态的,当函数或程序执行时,会创建自己的执行上下文推入执行上下文栈中,执行上下文可以认为是代码的一个执行环境,所有代码都是在执行上下文环境中执行的。

JavaScript执行上下文有全局执行上下文,和函数执行上下文。

执行上下文有一个变量对象,全局执行上下文的变量对象叫做全局上下文对象,函数执行上下文的变量对象叫做活动对象。

当一个函数要执行时,会把它的执行上下文推入调用栈,调用栈始终执行栈顶的代码,当函数的代码执行完成后就会把函数的执行上下文弹出栈顶。因为js最开始是进入全局环境,所以调用栈的栈底是全局执行上下文。

变量对象在执行上下文中。

以下面的代码为例
我们来看看[[scope]]

function wrapper() {
    function inner() { }
}

inner执行时的作用域链
在这里插入图片描述
wrapper执行时的作用域链
在这里插入图片描述

从作用域链来看,外部函数的作用域链里没有内部函数的变量对象,自然访问不到内部函数的任何东西,这也是在情理之中。
上面wrapper执行时的作用域链也可以认为是inner定义时的作用域链。

前置知识已经了解。

那么什么是闭包呢?以下都是我的认为,不敢说百分百正确。

闭包

首先,闭包一定不是一个函数。我更喜欢说,它是内部函数访问其它函数作用域里变量或函数的一种现象。
首先说一下我在写这篇文章前一段时间对闭包的一个认识。

只要在函数内部用到了其它作用域的变量那么就会产生闭包。

这句话不能说他是错的,而且也是我认为最接近闭包的一个解释。
最具权威的就是mdn了。
我们直接上代码。

let g = 10;
function a() {
    let a1 = 10, a2 = 20, a3 = () => { }; // 外层函数作用域
    let yx = 10;

    {   // 块级作用域
        let block1 = 10;
        let block2 = 20
        (function (e) {
            g; // 用到了全局作用域里的变量
            a1; // 用到了a函数作用域的变量
            a2; // 用到了a函数作用域的变量
            a3(); // 用到了a函数作用域的函数
            block1; // 用到了块级作用域的变量
            block2; // 用到了块级作用域的变量
            console.dir(arguments.callee); // 打印函数本身的引用
        })(5);
    }
    // 函数并没有保存到外部 而是直接执行了
}
a();

控制台打印结果
在这里插入图片描述

我们看到一个很眼熟的东西Closure

闭包(closure)是一个函数以及其捆绑的周边环境状态的引用的组合

这不就是mdn上的一个解释吗?
我们看到它保存了内部函数引用到的外层函数作用域里的几个变量和函数,a1,a2,a3。
但它却没有包含yx
很显然闭包只保存了用到的变量和函数,而且这些变量和函数所存在的作用域应该是函数作用域。
在打印结果中
块级作用域引用到的变量被保存在Block
全局作用域引用到的变量被保存在Script

其实这里我在想,BlockScript算不算是闭包的另一种表示。

闭包是什么呢?

mdn : 闭包(closure)是一个函数以及其捆绑的周边环境状态的引用的组合

闭包是其实就是将函数与这个函数用到的其它(函数)作用域里变量或函数进行捆绑的一种现象,因为他们捆绑在一起了,所以当这个函数还能访问到的情况下,与它捆绑在一起的变量和函数都不能被垃圾回收器回收,所以我们也经常说,闭包容易导致内存占用。

正常情况下产生的闭包,是不会有内存占用的危险,比如上面的代码,函数执行完后,其它地方根本不能访问到这个函数,所以函数会被垃圾回收器回收,与之形成闭包的变量和函数也将被释放。

上面函数我之所以打上括号,是因为我不太清楚是不是仅包括函数作用域。
但是既然mdn上的解释只是强调周边环境,那应该是包括了块级作用域和全局作用域。

好了我的看法大概就是这些。

有位网友说的很好,也很容易懂。我们来看一下。
在这里插入图片描述
其实他的解释跟我的解释差不多,只不过他解释的更通俗易懂。

闭包的意义

其实闭包的意义
我想说就是因为有闭包所以我们的函数才能在任何地方都能访问与它捆绑在一起的变量和函数。

然后就是闭包在我们开发中的意义
私有化变量这些大家应该都懂。我觉得没必要讲。

以上都是我的见解。

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

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

相关文章

英语不好,能不能学会编程?

编程的人都会问: 我英文差能学会编程吗?? 学会编程不须要多浅近的英语水平,想要学会编程,简略的英语水平足够了。当初的程序开发环境又很敌对,基本上关上之后不须要怎么配置,间接写代码就行&a…

Assignment写作摘要方面包含哪些内容?

英文Assignment摘要需要包含问题陈述、动机、方法、结果和结论五个要素。本文小编针对每个要素给出一些常用的句型,以供大家参考使用。 Assignment英文摘要五要素常用句型整理 1、问题陈述(problem statement)常用句型 陈述要解决的问题详解,这个问题又哪…

【JSP】EL表达式

EL表达式EL表达式干什么用的?EL表达式的使用面试题如何输出对象属性值?域中取数据注意事项EL表达式的空处理如何从Map集合中取数据如何从数组或者List集合中获取数据局部忽略EL表达式EL表达式的内置对象EL表达式的运算符EL表达式干什么用的? …

手把手教你写一个图片预览组件

一、前言 本篇主要介绍,vue项目手写一个图片预览组件,组件主要包括图片方法、图片缩小、显示原图、下载、复制等功能。 二、实现方式 首先我们需要做一个图片预览组件都有的功能表头,如下图 主要功能包括,放大、缩放比例显示、…

设计模式:02观察者模式--labview实现

引言 在观察者模式中,一种叫做被观察者的对象维护了观察者对象的集合,当被观察者对象发生改变时候,它会通知观察者。 在被观察者对象所维护的观察者集合中,能够添加或者删除观察者。被观察者状态变化能够传递给观察者。这样观察者…

路西德Lucid EDI项目测试流程

Lucid Motors路西德汽车拥有电动汽车制造、储能技术和代工生产等业务,目前已成功研制出其第一辆汽车Lucid Air,并开始对外销售。随着企业的不断发展,对自动化的要求也越来越高,作为制造型企业,Lucid早已实现机械自动化…

多个JDK版本可以吗:JDK17、JDK19、JDK1.8轻松切换(无坑版)小白也可以看懂

多个版本JDK切换 多个JDK:JDK17、JDK19、JDK1.8轻松切换(无坑版)小白也可以看懂 提示:看了网上很多教程,5w观看、32w观看、几千观看的,多多少少带点坑,这里我就把踩过的坑都给抹了 文章目录多个…

架构演进技巧

架构演进剖析 架构演进定义 定义:通过设计新的系统架构(4R)来应对业务和技术的发展变化 目的:1、应对业务发展带来新的复杂度;2、应用技术发展带来的复杂度新的解决方法 关键:1、新架构;2、…

UDS知识整理(五):安全访问——0x27服务

目录 一、0x27服务(安全访问)简介 二、0x27服务信息格式 (1)请求格式 (2)正响应格式 (3)负响应格式 三、0x27服务服务举例 (1)请求种子与发送KEY 一、…

实变函数与泛函分析基础

集合的运算 并集:1、任意两个集合 2、任意多个集合的并集或和集: 设 一族集合 ;由一切 的 元素组成的集合,其中 是固定指标集, 是 中变化的指标。 记为 ,可表示为 是 有限集, 记 …

CoreData 同步 iCloud 数据导致 App 启动超时被系统 watchdog 终止的原因及解决

问题现象 CoreData + iCloud 支持的 App 在启动时偶尔会出现被系统强制退出的情况,用 Xcode 也无法中断调试这种崩溃,查看真机上的崩溃日志如下: 如上图所示,我可以了解到 App 崩溃的原因是由于启动超时被系统看门狗(watchdog)强行关闭了: process-launch watchdog tra…

宇视雷达雷视交付|问题定位(素材收集篇)

雷达&雷视交付|问题定位(素材收集篇) 雷视一体机作为行业明星产品,具备交通信息采集、交通事件检测等功能,在交通领域的应用前景十分广阔。为了快速响应现场交付时问题定位的诉求,提升一线的素材收集规范性和效率…

回收站清空了怎么恢复?数据恢复,有这些就足够了

大家都知道,数据在回收站中会有一定的时间,但是被清空之后,数据就很难恢复了。回收站清空了怎么恢复?首先需要知道,被清空的文件可以分为两类。一类是重要资料,另一类是一些无关紧要的资料。找到我们要恢复…

Kotlin高仿微信-第14篇-单聊-视频通话

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

SpringMVC(八):SSM整合

文章目录 SSM整合 一、准备数据库表格 二、创建maven web项目并补充项目结构,准备好MVC模式下的主要目录 三、更新web.xml 文件和准备包结构 四、导入依赖 五、log4j2.xml 六、jdbc.properties 七、springMVC.xml配置文件 八、applicationContext.xml 九、…

Anaconda默认安装在C:\Users\xxx\.conda\envs中

目录 问题: 解决: 更改默认安装位置 移动已安装环境 问题: 解决: 更改默认安装位置 用记事本打开 C:\Users\zqk\.condarc 在最后插入 envs_dirs: - D://anzhuang//Anaconda3//envs 如若需更改pkgs,插入如下代…

如何使用OpenCV作图像或矩阵的逻辑运算

所谓逻辑运算,主要是指逻辑与运算、逻辑或运算、逻辑非运算、逻辑异或运算。 可用函数bitwise_and()实现图像或矩阵的逻辑与运算; 可用函数bitwise_or()实现图像或矩阵的逻辑或运算; 可用函数bitwise_not()实现图像或矩阵的逻辑非运算&#x…

oh-my-zsh 为 ls 命令自定义颜色

ls 命令默认显示的颜色是: 白色: 表示普通文件 蓝色: 表示目录 绿色: 表示可执行文件 红色: 表示压缩文件 蓝绿色: 链接文件 红色闪烁:表示链接的文件有问题 黄色: 表示设备文件 灰…

Java实现3DES加密解密(DESede/ECB/PKCS5Padding使用)

一、简介 3DES(又叫Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。 它相当于是对每个数据块应用三次DES加密算法。密钥长度是128位,192位(bit),如果密…

如何最简洁的使用iOS 开发证书 和 Profile 文件

如果你想在 iOS 设备(iPhone/iPad/iTouch)上调试, 需要有 iOS 开发证书和 Profile 文件。 在你拿到这两个文件之后,该如何使用呢? 证书使用说明: 1. iOS 开发证书:开发证书 (Devel…