全网最通透的“闭包”认知 · 跨越语言

闭包作为前端面试的必考题目,常让1-3年工作经验的JavaScripter感到困惑,其实主流语言都有闭包。

今天我们深入聊一聊[闭包], 查缺补漏!

 1. 以面试题 ·  投石问路 2. 以C#闭包 ·  庖丁解牛 3.    跨越语言 ·追本溯源   •  头等函数   •自由变量   •词法作用域4.  答面试题 · 返璞归真

1. 投石问路

调用下面函数,输出结果是什么样呢?

static void Closure1()
{for (int i = 0; i < 5; i++){                 Task.Run(()=> Console.WriteLine(i));}
}
//  输出:
5
5
5
5
5

是不是很意外?如何输出原本预期的 0,1,2,3,4。

bingo, 加一个临时变量就可以解决。

static void Closure2()
{for (int i = 0; i < 5; i++){int j = i;Task.Run(() => Console.WriteLine(j));}
}
// 输出:
3
0
1
4
2
//  多次执行的结果不一样,但是总是会保持输出 0,1,2,3,4 的乱序组合

以上闭包概念涉及到 Task任务,理解起来更加复杂,我们来看一个基础的C#闭包。

2. 庖丁解牛

一个闭包就是一个“捕获”了其生成的环境中、所引用的自由变量的函数。
这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

 static void Closure(){var x = 1;Action action= () =>{var y = 1;var result = x + y;Console.WriteLine(result);x++;};action();action();
}// 输出:23

我们首先定义了一个委托action,它引用了“x”变量(x变量既不是入参,也不是委托内的局部变量), 这个变量将被action"捕获”,被自动添加到action 的运行环境。

当我们执行action时,原始的“x”已经脱离了它被引用时的作用域环境,但是两次执行能输出2,3 说明它脱离原引用环境仍然能用。

当你在代码调试器(debugger)里观察“action”时,可以看到C#编译器为我们创建了一个Target属性,里面封装了 x 变量:

源码追溯,委托继承自Delegate抽象类,Delegate类有个Target 属性(获取当前委托调用实例方法的实例类) 。
至此可以猜想: 我们每次执行委托,实际是是执行某个匿名类上的实例方法。

都说了闭包是跨越语言的设计, 至少我知道 JavaScript C# Go都有闭包。

3. 追本溯源

闭包是词法闭包的简称,维基百科上是这样定义的:
在计算机编程中,闭包是在词法环境中绑定自由变量的头等函数”。

头等函数

头等函数( First Class)意味着语言将其视为第一类数据类型的函数, 意味着你可以将函数分配给一个变量(或作为参数传递),然后像正常函数一样调用。

很明显,C#常使用的委托(C#委托的演进:匿名函数-->lambda表达式)是头等函数。

Func<string,string> myFunc = delegate(string var1){return "some value";   };
Func<string,string> myFunc = var1 => "some value";  
string myVar = myFunc("something");

自由变量

自由变量是在匿名函数/lambda表达式中被引用的变量,它不是函数的参数也不是函数的局部变量。

var myVar = "this is good";
Func<string,string> myFunc = delegate(string var1){return var1 + myVar;   };

词法作用域引用的自由变量,注意,是引用自由变量,并不是使用当时自由变量的值

☺️通俗点, 就是告知这个变量环境,我这个匿名函数等会执行时要用到这个变量;如果我没被销毁,你不能销毁我引用的自由变量。

我们再回过头来看[投石问路]的面试题。

4. 返璞归真

首先你要知道:循环内开启的Task任务,并不保证执行顺序。

Demo1:输出5,5,5,5,5

这是因为在 for循环内,开启了5个Task任务,每个任务均引用了自由变量i (相对于每个任务执行环境,i 属于全局变量);
for循环先执行完,i=5, 5个任务输出时自然得到值5。

为什么加上临时变量就能输出"预期"?

Demo2:输出乱序的0,1,2,3,4

这是因为 在for循环内,每次循环j均拷贝自当时的i,每个任务均引用了自由变量 j (每个任务执行环境均维护了一个变量j);
任务乱序执行时依旧能获取本任务绑定的自由变量j。


有这样的认知,理解JavaScript 闭包也就不难了。

# 总结

本文屏蔽语言差异,理清了[闭包]的概念核心: 头等函数、自由变量,不仅能帮助我们应对多语种有关闭包的面试题, 也帮助我们了解[闭包]在通用语言中的设计初衷。

原创不易 点个在看支持下~

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

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

相关文章

北大最神博士论文:为什么学校打印店老板大多是湖南人?

导读&#xff1a;北京大学社会学系博士冯军旗的一篇论文&#xff0c;虽然是话题看起来有些奇葩&#xff0c;但仍然考据严谨&#xff0c;很有价值。01 写在前面&#xff08;非论文部分&#xff09;多媒体出版行业中&#xff0c;充满油墨芬芳的印刷总是长盛不衰。特别是在大学校园…

技术分享 | jaeger链路日志实现

源宝导读&#xff1a;随着企业应用越来越复杂&#xff0c;内部的调用链条越来越长&#xff0c;性能问题也变得越来越难以定位和排查&#xff0c;为了应对此问题&#xff0c;我们在移动平台中引入了“jaeger调用链追踪工具”&#xff0c;帮助我们高效定位云端服务的性能问题。本…

IT资料,重磅来袭!

现在IT行业越来越火爆&#xff0c;技术的更新也越来越快&#xff0c;不好好充实自己的话&#xff0c;就会被淘汰。小编这几年一直有意识地收集IT行业相关的资料&#xff0c;现在已经拥有8G左右的资料&#xff0c;如区块链、Python、大数据、人工智能深度学习等方面的资料&#…

荐书 | 10本书给你计算机大师思维

《黑客与画家》作者&#xff1a;保罗格雷厄姆 / 译者&#xff1a;阮一峰美国互联网界如日中天的教父、哈佛大学离经叛道的博士保罗格雷厄姆著作&#xff01;一本书&#xff0c;你不曾想到的视角&#xff0c;彻底颠覆你对世界的认识&#xff01;美国亚马逊、纽约时报超级畅销书&…

php按时间分组的sql语句,(SQL语句)按指定时间段分组统计

---------------------------------------Author : liangCK 梁爱兰--Comment: 小梁 爱 兰儿--Date : 2010-01-02 16:47:10---------------------------------------> 生成测试数据: #tbCREATETABLE#tb(列名1varchar(12),时间datetime)INSERTINTO#tbSELECT03174190188,2009…

NET问答: 说说你对 LookupTKey, TElement 的看法 ?

咨询区 dan-gph&#xff1a;MSND 上对 Lookup 做了如下的解释。Lookup<TKey, TElement> 类似于 Dictionary<TKey,TValue>, 不同点在于 Dictionary<TKey, TValue> 中的key对应的是单个value&#xff0c;而 Lookup<TKey, TElement> 中的 key 对应的是一个…

最多金的编程语言Top10:Python第3,R第10,你猜第1是谁?

导读&#xff1a;如果你还在纠结选哪门编程语言来开启你的码农生涯&#xff0c;这将是你的最佳指南。本文绝非标题党&#xff0c;而是基于大量数据和为期两周的深入探究&#xff0c;在18年初&#xff0c;对IT行业的现状、趋势以及预测进行客观观察&#xff0c;让大家对编程语言…

[转贴]制作windows 2003自动安装盘-集成补丁/Raid及硬件驱动

从事网游行业的工作人员&#xff0c;如果一款游戏上线&#xff0c;必须上大量服务器。用品牌机引导盘装系统&#xff0c;再打个补丁&#xff0c;速度真让人不敢恭维。为了提高效率&#xff0c;就尝试制作一张集成系统补丁/RAID及硬件驱动自动安windows 2003系统盘。下面以品牌机…

4月 .NET 线上 Meetup,快来报名

点击蓝字关注我们.NET 6 preview 2 在3月11日已经发布&#xff0c;.NET 6 将是 .NET Core 3.1 之后的第一个 LTS 版本&#xff0c;也是微软开启全平台统一一个 .NET 计划以来的第一个 LTS 版本&#xff0c;意义不可谓不大&#xff0c;那么 .NET 5/6 又会带来哪些新特性呢&#…

NP完全性理论与近似算法

一、图灵机根据有限状态控制器的当前状态及每个读写头读到的带符号&#xff0c;图灵机的一个计算步可实现下面3个操作之一或全部。改变有限状态控制器中的状态。清除当前读写头下的方格中原有带符号并写上新的带符号。独立地将任何一个或所有读写头&#xff0c;向左移动一个方格…

阿里25k 百度25k,招WPF!

.NET5打通7大开发方向&#xff0c;CLR超高性能&#xff0c;.NET6支持Blazor嵌入WPF&#xff0c;还有MAUI跨平台UI解决方案&#xff0c;都是.NET的利好&#xff0c;也是WPF的利好。牛年跳槽季&#xff0c;.NET在客户端方向一骑绝尘&#xff0c;阿里影视、百度地图&#xff0c;以…

掌握神经网络模型的快捷方式

TensorFlow是Google基于DistBelief进行研发的第二代人工智能学习系统&#xff0c;其命名来源于本身的运行原理。Tensor&#xff08;张量&#xff09;意味着N维数组&#xff0c;Flow&#xff08;流&#xff09;意味着基于数据流图的计算&#xff0c;TensorFlow实际上就是张量从流…

.Net项目模板(Project Template)

你有没有这样的感觉&#xff0c;开启一个新项目时&#xff0c;总是做一堆体力活——项目的结构层次&#xff0c;常用日志库&#xff0c;OpenAPI库&#xff0c;ORM库&#xff0c;的引入&#xff0c;权限认证方式选择添加&#xff0c;配置文件重新归置存放等等。公共框架的部分总…

谈通过测试与失败测试

在软件测试技术中&#xff0c;现有的测试方法、测试技术中均未提及到通过测试与失败测试。 而在实际项目测试过程中&#xff0c;很多项目组却再应用该方法。虽然该方法被采用&#xff0c;但是很多人对通过测试与失败测试理解并不透侧&#xff0c;在实际使用过程中并未按统一的标…

100个微信小程序的源码公开分享

现在微信小程序越来越火&#xff0c;小编一直有意识地收集微信小程序源码&#xff0c;至今已经拥有100个小程序的源码&#xff0c;有gank、LOL战绩查询、百度小说、豆瓣电影、手势解锁等。现在&#xff0c;小编准备将这些资料免费分享给大家&#xff01;gankLOL战绩查询百度小说…

家里在一二线城市有很多套房是什么体验?答案太颠覆!

作者&#xff1a;匿名来源&#xff1a;知乎&#xff08;图片&#xff1a;网络&#xff09;“家里在一二线城市有很多套房是怎么的一种体验&#xff1f;”这是知乎上一个浏览超600万的话题。其中一个答案非常颠覆&#xff0c;获得高赞。作者的观点是否正确见仁见智&#xff0c;但…

希尔排序听起来有点难,其实很简单

前言直接插入排序当待排序数据的顺序和期望排序结果相反时&#xff0c;排序效率是最差的&#xff1b;上次聊到的折半插入排序只是减少有序列表的比较次数&#xff0c;而对于整体数据遍历次数还是没有得到优化&#xff1b;接下来要说的希尔排序就是针对整体数据进行优化&#xf…

等我敲完这行代码,就和你离婚!

工作是高端大气上档次&#xff0c;工资是低调奢华接地气&#xff01;我们叫做“程序猿”&#xff0c;也叫“攻城狮”&#xff01;但是往往城还没攻下来&#xff0c;我们的头发就先掉下来&#xff01;我们最喜欢听的一句话就是☟段子一“等我敲完这行代码&#xff0c;就和你离婚…

深夜,学妹遇到了数据分析师生涯的第一个疑问

大家好&#xff0c;我是大鹏&#xff0c;目前是一名数据分析师。自从上次学妹深夜给我发微信&#xff0c;询问数据分析师招聘要求和需要掌握的技能&#xff0c;已经过去2个月了。直到昨天&#xff0c;我再次收到了学妹的召唤&#xff1a;当天深夜 学妹深夜求助&#xff0c;定是…

你知道WPF与WinForms的区别吗?

介绍WPF的缩写指微软的Windows Presentation Foundation&#xff0c;而WinForms是Windows Forms Applications的简单组合。这两个都是微软的Windows应用程序图形用户界面&#xff0c;开发人员可以使用它们来开发Windows桌面应用程序。本文重点介绍两种开发Windows桌面应用程序的…