前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript中的闭包到底是什么?

JavaScript中的闭包到底是什么?

作者头像
人工智能小咖
修改2020-04-26 10:11:42
5760
修改2020-04-26 10:11:42
举报
文章被收录于专栏:人工智能小咖人工智能小咖

即使是短暂接触JavaScript的初学者,想必也一定听说过“闭包”。本文将介绍有关闭包的全部内容,但文中并不会经常出现这个词。

请认真阅读以下代码:

1- function greeting(){2- var message="Hello World";3- return message; }4- const message=greeting();

执行上述代码会发生什么呢?

再介绍几个小伙伴,它们将有助于理解上述代码。

“执行线程”:为简单起见,它将负责代码的逐行检查和执行。

将“执行线程”看做单独的个体,当这个小伙伴位于第1行时,会发生什么呢?

“执行线程”从第1行开始,找到关键字function

创建名为“greeting”的标签,在Global Memory中存储全部函数

“执行线程”跳过函数中的代码,移至下一行

在此情况下,“执行线程”会跳过第2、3行,到达第4行

现在,这个小伙伴位于第4行。这个时候会发生什么呢?

“执行线程”发现标记为“message”的常数关键字

“执行线程”很清楚自己的任务是在Global Memory中分配新的内存空间

现在,“执行线程”并不确定在标签中存储何值

“执行线程”现在看到了greeting后面的“()”标志

它很清楚自己在看到function invocation或calling a function(这个说法更常用)时需要做什么。

是时候介绍一下新伙伴了。它名为“调用栈”,也被称为“执行栈”或“程序栈

“调用栈”有多种相关用途,但其主要用途是在所有活跃函数结束执行后,追踪其返回控制的点

因此,greeting函数被放入了“调用栈”,并创建了一个新的Execution context。现在,之前出场的老朋友“执行线程”陷入了全新的执行环境之中

“执行线程”并不知道该如何逃离这个新环境。所以,它开始做自己擅长的事情(逐行读取并执行代码)

因此,“执行线程”小伙伴将标记为“message”的变量存储在Execution ContextLocal Memory

现在,“执行线程”到达了第3行,找到了关键字“return

执行线程”检查自己是否找到标记为message的变量。它首先检查execution context的local memory

找到后它很高兴地将值返回到了Global Scope中的message标签

因此,greeting从“调用栈”中弹出

最后,Execution context被破坏了

大家可能认为:

“好吧,卖弄得够多了,可是‘闭包’这个家伙在哪呢?这些不过是正常函数的执行方式!!”

是啊!!笔者知道各位都很聪明,对这些内容已经了如指掌。但请各位耐心等待,以上这些内容是接下来要讲解的闭包的基础。

现在来看一看更复杂的代码:

1- function IamaSimpleFunction(){
2- var message="Hello everyone!";
3- function greeting(){
4- return message;
 }
5- return greeting;
}
6- const greetEveryOne=IamaSimpleFunction();
7- greetEveryOne();

那么现在开始讲解“不那么简单的函数”。

这次仍然需要“执行线程”小伙伴的帮助

执行线程”开始逐行读取代码。在第1行,它遇到了function关键字。像往常一样,它将该关键字转到Global Memory,并给名为IamaSimpleFunction的函数分配内存

执行线程”会跳过第2、3、4、5行,到达第6行。它创建了一个存储greetEveryOne的内存空间,但像往常一样,它不知道该标签现在应存储什么。

现在,它可以看到函数的执行情况,创建了一个新的execution context,并将其放入了“调用栈

现在,如之前示例所述,“执行线程”将值“Hello everyone”存储在Local Memory的message标签内

同样,第3行的“greeting”函数也存储在Execution Context的local memory中

下一行中出现了“return”。“执行线程”对Local Memory进行检查,看看是否有名为greeting的内容

它将存储值(函数)返回到存储在Global Memory的greetEveryOne标签中

接下来是笔者最喜欢的环节

摧毁一切!!!!

Execution context被破坏了,它的Local Memory也是如此。因此该函数从“调用栈”中弹出。

接下来是一个有趣的环节。大家觉得输出结果会是什么呢????

进行合理分析后,笔者推断:

“由于IamaSimpleFunction函数返回了,它的Execution Context被破坏了,除此之外,local memory中的所有东西也都被破坏了。因此,简单地说,输出结果将会是未定义变量或者与无法找到的message变量有关的错误。”

但输出结果非常出人意料,它竟然是:

Hello everyone!

是的,笔者知道各位对此感到非常震惊!!!

好,不卖关子了!!一起来揭开它背后的奥秘吧。

返回“greeting”时,检查其是否需要当前Current Lexical Scope(代码所在地)中的内容。在这种情况下,“greeting”位于IamaSimpleFunction函数内部

它将所有内容打包,放入名为[[scope]]的私有作用域中

现在,即使外部函数被返回,且execution context遭到破坏,greeting也将在[[scope]]中存储message值

应用于global context时,它知道该去哪里寻找message值。没错,各位!去[[scope]]里面找

JavaScript的这一功能就叫“闭包”

确实没什么特别的!它只是一个从高阶函数返回的函数,可以存储那些存在于其词法范围内的变量和对象。

好的各位,就介绍这么多。

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系外文翻译前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档