到底什么是闭包

Swift ——闭包 之前在代码的书写过程中,我们已经或多或少的接触过函数,函数本身也有自己的类型,它由形式参数类型,返回类型组成。如果将函数传递给a变量,那么就可以借助a来调用方法,这里addTwoInts代表函数类型。如果出现了同名函数,但是返回值或者参数不一样,那么就需要指明函数类型。否则就会报 ambiguous user of *** 错误,因为这个时候编译器不知道要给a赋值哪一个参数。把函数赋值给a,那么a里面储存的是什么呢? 运行后打印a,这里看懂存储的是函数类型.这里函数类型也是引用类型,当把函数赋值给a的时候, 阅读详情

一开始接触闭包有些问题一直绕不过去,可了看其他的资料,也从网上查了查,下面是我总结的一些东西:

“官方”的解释是:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

通俗的讲:就是函数a的内部函数b,被函数a外部的一个变量引用的时候,就创建了一个闭包。

(这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b)

   function a(){
           var i=0;
           function b(){
              alert(++i);
           }
              return b;
       }

 var c = a();
        c();

 

闭包的特性:

①.封闭性:外界无法访问闭包内部的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口;
②.持久性:一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在
系统中,闭包中的数据依然存在,从而实现对数据的持久使用。

优点:

① 减少全局变量。

② 减少传递函数的参数量

③ 封装;


   缺点:
 使用闭包会占有内存资源,过多的使用闭包会导致内存溢出等.




最简洁、直击要害的回答,我能想到的分别有这么三句

1、闭包是一个有状态(不消失的私有数据) 的函数。

2、闭包是一个有记忆的函数。

3、闭包相当于一个只有一个方法的紧凑对象
(a compact object) 。

上面这三句话是等价的,而其中第 3 句最精妙,可以指导何时、如何用好闭包,后面我会详细分析。

澄清概念

MDN(Mozilla Developer Network)上的闭包定义是这样的:

Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, the function defined in the closure 'remembers' the environment in which it was created.

Closures - JavaScript

关于什么是闭包以及有哪些典型的用法(实例)、注意事项,MDN 其实已经解释得很清楚了,建议英文好的同学先耐心读完这篇好文。

我换个角度来谈谈。

首先,很明确——闭包是一个函数,一种比较特殊的函数。什么是函数?函数就是一个基本的程序运行逻辑单位(模块),通常有一组输入,有一个输出结果,内部还有一些进行运算的程序语句。所以,那些仅仅说闭包是作用域(scopes)或者其它什么的,是错误的,至少不准确。

MDN 还有一段解释:

A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.


理解了以上这些概念,关于“什么是闭包”您的大脑中是否出现了下面这张图(用 UML 组成结构图来表示):

有实例有真相

让我们先回顾下传统函式的机理。

我们说普通函式自身是没有状态的(stateless),它们所使用的局部变量都是保存在函式调用栈(Stack)上,随着函式调用的结束、退出,这些临时保存在栈上的变量也就被清空了,所以普通函式是没有状态、没有记忆的。

例如下面的普通函式 inc(),不管执行多少次都只返回 1:

var inc = function () {
  var count = 0;
  return ++count;
};

inc(); // return: 1
inc(); // return: 1


为什么这样?这是因为这里的 count 只是一个普通函式的局部变量,每次执行函式时都会被重新初始化(被第一条语句清零),它不是下面例子中可以保持状态的闭包变量。

再来看闭包的例子。

这可以说是一个最简单的 JavaScript 闭包的例子,这里的 inc() 是一个闭包(函式),它有一个私有数据(也叫闭包变量) count(即函式中的第 2 个 count)。

var inc = (function () { // 该函数体中的语句将被立即执行(IIFE)
  var count = 0; // 局部变量 count 初始化
  return function () { // 父函式返回一个闭包(函式引用)
    return ++count; // 当父函式 return(即上一个 return)后,这里的 count 不再是父函式的局部变量,而是返回结果闭包中的一个闭包(环境)变量。
  };
}) ();

inc(); // return: 1
inc(); // return: 2

我还未研究过任何 JavaScript 引擎(解释器)的源码,所以只好根据常识与逻辑作些合理的推测。

在本例中第 2 个 count 作为闭包的私有数据,很可能是被 JS 引擎存放到了堆(Heap)上,而且是按引用(byref)来访问,所以可以保持状态,实现计数累加;而第 1 个 count 只是存放在函式调用栈(Stack)上的局部变量,于是那个 IIFE 父函式一退出它就被销毁了,它的作用主要是用来初始化(赋值)给担任闭包变量的第 2 个 count。

可见两个 count 虽然同名,却是两个截然不同的变量!

这点恐怕正是许多 JS 初学者(包括当年的我)屡屡见到闭包时,感到最为大惑不解的地方吧。我们以为父子函式里外两个同名的变量是一回事,而其实它们不是,也不知道这背后究竟发生了哪些变化。

关于上面提到的内存管理模型中栈与堆的区别,建议不熟悉的同学可以参考下图和文章:

MDN: Concurrency model and Event Loop


闭包 vs. 对象

实现同样的计数功能,不用闭包怎么写?同样以 JavaScript 为例,用传统的 OOP 来写:

var obj = {
  count: 0,
  inc: function () {
    return ++this.count;
  }
};
obj.inc(); // count: 1
obj.inc(); // count: 2

用闭包与用对象,区别在哪?

其实主要区别就一个:这里用的是普通对象 obj 的方法(函数)inc,让 count 作为 obj 的成员变量来保存数据。而前面第一个例子直接用闭包函数 inc 的话,连 obj 这个对象也可以省掉,让 count 直接成为 inc 闭包内部所保存的状态(环境)变量,这样写起来就比传统的 OOP 更为紧凑,前者用 inc(),而后者用 obj.inc(),尽管两者最终实现的功能和效果基本是一致的。

通过以上这两个小例子的比较,你可以充分体会到在 JavaScript 中,函数(functions)作为首席/头等公民(first-class object)的地位。由于有了闭包,加上在 JavaScript 中函数也是对象——一个函数可以像一个传统的对象那样拥有自己的属性、私有数据和状态(不会随着栈而清空),许多简单功能的实现可能无需再借助 objects 了。

关于闭包与对象之间的联系,MDN 也说得很清楚:

A closure lets you associate some data (the environment) with a function that operates on that data. This has obvious parallels to object oriented programming, where objects allow us to associate some data (the object's properties) with one or more methods.

Consequently, you can use a closure anywhere that you might normally use an object with only a single method.


你看,闭包是不是相当(近似)于一个只有一个方法的对象?只有一个公开方法,而且成员数据几乎全私有(闭包)的对象,自然是一个紧凑版的对象了。

实际应用

读完本文,估计您对“到底什么是闭包”已经有了比较准确、细致的了解。下一个关心的问题,一定是:闭包在 Web 和 JavaScript 开发中有哪些实际的应用呢?

最后,推荐您继续阅读我的这篇文章,看看闭包作为紧凑对象的一个经典应用,如何利用一个非常简单的闭包来实现前后端开发中普遍存在的二元状态切换(toggle)功能:

JavaScript 设计模式之开关闭包(Closure Toggle)

参考

MDN: Closures - JavaScript

Wikipedia: Closure (computer programming)

【闭包】前端的“保护神”——闭包详解+底层原理 它们能够保持对外部数据(如事件触发时的状态、函数参数等)的访问,即使在异步操作完成后,闭包仍然能够访问这些数据。你可以将某些功能封装在闭包内部,外部只能通过公开的方法调用它们,从而达到隐藏细节、减少外部依赖的目的。闭包提供了数据封装的能力,可以将状态和行为封装在一个函数内部,并通过暴露的接口与外部进行交互。闭包可以用于权限管理和角色管理的场景中,通过闭包来封装不同角色的权限信息,从而提供灵活的权限控制。是私有的,外部无法直接访问。,即使这个函数在外部被调用时,依然能访问到其定义时的父函数的局部变量。 阅读详情

相关推荐

AMG8833红外测温实战:在STM32F103上做个简易人体感应与温度报警器

本文详细介绍了如何在STM32F103上使用AMG8833红外测温传感器构建人体感应与温度报警系统。通过硬件连接方案、驱动代码开发、人体检测算法实现及报警系统设计,展示了如何利用8x8红外温度矩阵实现智能监测功能。文章包含实用的初始化流程、温度数据读取优化和低功耗策略,为创客项目提供完整解决方案。

weixin_33725239的博客 392

对闭包的理解

理解闭包

hddlsj的博客 2582

Unity3D Lua与C#的相互调用与性能剖析详解

在游戏开发中,经常会遇到Lua与C#之间的相互调用的情况。本文将详细介绍Unity3D中Lua与C#的相互调用的方式,并对其性能进行剖析。对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!一、Lua与C#的相互调用方式Lua调用C#在Unity3D中,可以通过Lua调用C#的方式来实现Lua与C#的相互调用。具体步骤如下:(1)首先需要在Unity3D项目中导入Lua的相关库,例如tolua或者xlua。

weixin_49669470的博客 1211

什么是闭包?(详解闭包)

什么是闭包? 闭包的优点。 闭包的缺点。 闭包的作用。 闭包

我只是个很菜的前端 1万+

新手也能懂的Simulink汽车二自由度建模:从公式推导到模型搭建全流程

本文为新手提供了在Simulink中搭建汽车二自由度模型的完整实战指南。文章从模型核心概念讲起,详细讲解了如何将车辆动力学方程转化为状态空间模型,并逐步指导在Simulink中实现从参数设置、模块搭建到仿真验证的全过程。通过阶跃转向测试和参数影响分析,帮助读者直观理解车辆转向特性,并提供了实用的模型扩展思路与常见问题排查技巧。

weixin_29047919的博客 213

AI+医疗:多模态模型让肺结节诊断准确率突破95%+的实战方案

多模态融合是必由之路:单一影像模型难以突破95%准确率,必须整合临床、生物标志物等多维数据跨模态注意力机制是核心:简单拼接效果差,注意力机制能自动学习各模态权重,提升融合效果临床适配比技术先进更重要:模型输出必须符合医生诊断习惯,提供可解释的决策依据持续学习是长期成功的关键:医疗数据分布不断变化,模型必须具备自适应能力多学科协作是保障:放射科、胸外科、病理科、AI工程师共同参与模型设计与优化。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1022

闭包是什么?五分钟带你了解闭包

你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包。一个闭包是一个可以自己拥有独立的环境与变量的的表达式(通常是函数,因为ES6有了块级作用域的概念)。可以先点击上面链接查看MDN对闭包的讲述。闭包是指有权访问另一个函数作用域中的变量的函数。这样闭包的作用就很明显了可以在函数的外部访问到函数内部的局部变量。让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。

寒烟说的博客 3万+

2025年再论 SAP ABAP 系统经典的三层架构的理解

【摘要】本文基于作者19年SAP开发经验,深入解析SAP经典三层架构在S/4HANA时代的演进与实践。数据库层从多数据库支持转向HANA专属,通过SQLScript实现计算下推;应用层以ABAP平台为核心,融合OData和RAP等现代开发范式;表现层从SAP GUI过渡到Fiori Launchpad为主导。文章通过真实案例(如月末关账优化、ATP检查改造)展示三层协作如何提升性能,并探讨了本地/云/混合部署策略。全文贯穿SAP官方技术文档参考,为开发者提供体系化架构认知和实践指导。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 754

什么是闭包?

闭包也是面试高频题目——通过这篇文章你可以了解什么是闭包,闭包存在的意义,以及闭包的优缺点。

Concise200的博客 1万+

深度强化学习 | 详解基于价值的强化学习DQN算法(附Pytorch实现)

深度Q网络DQN的核心原理是通过经验回放池和目标网络技术拟合高维状态空间,是Q-Learning算法的深度学习版本,本文分析DQN的基本算法,并给出训练实例和实际案例

FRIGIDWINTER的博客 4985

YOLOv8改进 | 融合篇,YOLOv8主干改进融合网络之MobileNetV3+CA注意机制,助力涨点

MobileNetV3通过结合硬件感知网络架构搜索(NAS)和NetAdapt算法,通过新颖的架构改进进一步提升了性能。YOLOv8中的主干网络替换成MobileNetV3+引入CA注意机制

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1881

闭包:什么是闭包、闭包的作用、闭包的解决

学习闭包我们要清楚函数作用域、内存回收机制、作用域继承。作用域我们可以认为它是一个封闭的盒子,只让它在这个盒子里面进行操作,也可以称这个盒子为独立作用域。在js中,一个函数要执行时就会在内存里面创建一个独立作用域————封闭的盒子。比如在函数中第一一个变量,只能在函数这个独立作用域中使用(也就是封闭的盒子)。只要跳出这个作用域,就找不到该变量了。而且函数执行完毕之后,这个独立作用域或(封闭的盒子)就会删除。有一种情况下这个封闭的盒子是不会删除的,那就是“闭包”,后面会讲到。内存回收机制就是不在用到的内存空间

weixin_56266471的博客 6万+

使用 ChatGPT Store 里的工具给 ABAP 制作 Logo,效果一般

在编程领域中,Domain Specific Language(DSL)是一种特定于某一问题领域的计算机语言,诞生目的就是为了解决该领域特定类型的问题。在 ChatGPT 官网的 GPT Stores,也有很多已经预先配置完毕,专用于某一特定领域的 GPT 工具,OpenAI 将其分类如下。第三个问题是 Logo 的配色,提供蓝白,黑绿和灰黄,以及自定义调色板四种选择。这个 GPT 设计了四个问题,通过一问一答的方式,获得使用者想创建 Logo 的细节。这次的复杂度调成最低的 1,感觉还是有点花里胡哨的。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 507

【集合论】关系闭包 ( 自反闭包 | 对称闭包 | 传递闭包 )

一、关系闭包 、 二、自反闭包 、 三、对称闭包 、 四、传递闭包 、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 6万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【集合论】关系闭包 ( 关系闭包求法 | 关系图求闭包 | 关系矩阵求闭包 | 闭包运算与关系性质 | 闭包复合运算 )

一、闭包求法 、 二、求闭包示例 ( 关系图角度 ) 、 三、求闭包示例 ( 关系矩阵角度 ) 、 四、闭包运算与关系性质 、 五、闭包复合运算 、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 2万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

什么是闭包,对闭包的理解,闭包的用途及优缺点

什么是闭包,对闭包的理解,闭包的用途、优缺点及注意事项

weixin_48644617的博客 3万+

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Swift 闭包

必报是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)一级其他一些编程语言中的匿名函数(Lambdas)比较相似。闭包可以捕获和存储其所在上下文中任意常量和变量的引用。被称为包裹常量和变量。Swift 会为你管理在捕获过程中涉及到的所有内存操作。在Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下return。

xiaoxiaobukuang的专栏 2089

闭包、闭包应用场景

闭包、闭包应用场景

weixin_45463061的博客 4861

闭包、自动闭包、逃逸闭包

闭包是自包含的功能块,可以在代码中被传递和使用,它能够捕获和存储其所在上下文中的任何常量和变量的引用。在 Swift 中,闭包类似于其他语言中的匿名函数(lambda)或块(blocks),但提供了更灵活和强大的功能。

Made In SQL 1416

自反闭包、对称闭包、传递闭包、正闭包、克林闭包(个人感悟)

自反闭包、对称闭包、传递闭包、正闭包、克林闭包、自反传递闭包、离散数学、自动机

归忆_AC的博客 6551

用代码实现自反闭包,对称闭包,传递闭包

目录 一、自反闭包 二、对称闭包 三、传递闭包 四、代码实现 五、运行结果 六、总结 一、自反闭包 理论很简单,就是R并上它的对角线全为一即可,比较容易实现 二、对称闭包 就是R并上它的逆 三、传递闭包 这个在上一篇博客上也说啦,在此不再赘述 四、代码实现 #include<stdio.h> #define N 100 int main() { int n,i,j,k,a[N][N],b[N][N],c[N][N]={0}; scanf("%d",&

crhxiyhx的博客 7237

闭包:什么是闭包,闭包有什么用

函数之间的嵌套,内层函数能引用到外层函数的变量或者形参。学习闭包我们要清楚函数作用域、内存回收机制、作用域继承。作用域我们可以认为它是一个封闭的盒子,只让它在这个盒子里面进行操作,也可以称这个盒子为独立作用域。在js中,一个函数要执行时就会在内存里面创建一个独立作用域————封闭的盒子。比如在函数中第一一个变量,只能在函数这个独立作用域中使用(也就是封闭的盒子)。只要跳出这个作用域,就找不到该变量了。而且函数执行完毕之后,这个独立作用域或(封闭的盒子)就会删除。

m0_74454396的博客 1092

什么是闭包,闭包是怎么产生的,闭包的应用在什么地方

目录 什么是闭包 闭包是怎么产生的 闭包的使用场景 使用闭包的注意点 一、什么是闭包 简单来说: 闭包就是能够读取其他函数内部变量的函数。 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。 所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。 创建闭包最常见方式,就是在一个函数内部创建另一个函数。一个简单...

qq_42817747的博客 7102

啥是闭包

啥是闭包 我一定要给这个闭包搞明白 离散数学中: 关系的闭包: 一个关系R的闭包,是指加上最小数目的有序偶而形成的具有自反性,对称性或传递性的新的有序偶集,此集就是关系R的闭包。 闭包的定义是,包含指定集合的满足在某个运算下闭合的最小集合。 离散数学中,闭包是一个集合,什么的集合呢? 关系的集合?还是集合元素的集合。 集合里面的元素是什么呢? 要讲清楚这个问题,要引入闭合的概念。 闭合指的是在一个集合上执行某种运算,得到的结果还是这个集合的元素,那么就说该集合在这个运算操作下构成闭合。 既然有闭合那就肯定有

qq_35862309的博客 9638

关系的闭包

闭包: 设 是 上的关系,如果 不具有 自反 (对称,传递)性, 我们希望 添加 一些 有序对,构成 具有上述性质,同时我们希望最小。 数学语言描述: 1. 具有自反(对称,传递)性质 2. 3. 任何包含 的自反(对称,传递)闭包,都有 闭包的记号: 自反闭包: 对称闭包: 传递闭包: 集合观点: 对于 上的关系,有 ...

海绵的博客 4993
上一篇: 【H5】localStorage、sessionStorage用法总结
下一篇: jquery的事件委托-bind,live,delegate,on的区别
wy_Blog
博客等级 码龄10年 68粉丝 72原创
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值