前端面经高频手撕-js面试三板斧-闭包(1)-- 初识闭包

文章探讨了前端面试中的常见知识点——闭包,包括它的定义、作用,以及在模块化和treeshanking优化中的表现。通过代码示例展示了如何在Chrome的开发者工具中观察闭包,并指出即使在非函数嵌套的情况下,如果内部函数引用了外部变量,也会形成闭包。文章还提到了Promise和事件循环的相关内容,并提供了面试问题的解答。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

快速阅读

如果你已经很了解闭包,那么可以直接跳到最后的们面试实战环节!~

何为三板斧

目前看了近期的一些面经,发现前端面试的高频三板斧:闭包,事件循环,Promise。当然也有看到async/await的内容,这部分在async/await 原理及简单实现中已经阐述,但是这篇文章写于三年前,随着时间的推移,对于同一问题的思考变得不一样了,所以这一部分将面经之外单开一个文章来阐述。

三板斧将结合 结构化的总结前端面经逐步完善到我们的知识库里。

最后 还请大家关注,点赞,评论,收藏,转发,这对我的创作很重要,谢谢各位大佬,老爷。

闭包的思考

闭包的大部分文章,都在讲述闭包是如何产生的,闭包的优缺点,闭包的内存泄露。

但是如果仔细思考,难免会有一些疑问:

  • 在tree shanking情况下,闭包会被如何编译?
  • 我在项目中不会明显的写function套用function的情况,大多使用模块化,那么闭包是否还存在?

何为闭包,我怎么看到它?

MDN给的解释是闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

总结就是闭包是从内部函数访问外部函数作用域的一种形式,它必须存在于函数中,且是函数为内外的关系,闭包必须跟随函数创建而创建。

说了这这么多年的闭包,我们一直都觉得是一个抽象的概念,那么有没有具体点的方式来看到闭包呢?

首先准备如下代码

 //闭包function closure_Fn() {var num = 1;return function () {return ++num;}}var add = closure_Fn();console.dir(add); 

以chrome 为例,在旧版本中,我们可以通过console.dir打印函数的方式,在scopes来获得闭包的信息. 上文代码执行后,将在console面板打印出

在新版中,我们在debugger的位置查看断点调试器。

此时显示出了该位置有一个闭包变量。本文个人使用新版的浏览器,所以会以断点的形式来查看,如果有使用旧版的同学,也请帮忙查看是否正确。

如上的代码,我们重新修改下

 //闭包function closure_Fn() {var num = 1;function add() {debuggerreturn ++num;}add()}closure_Fn() 

这段代码与刚才的不同,是没有return函数进行调用,而是直接执行了,那么在这种情况下,是否会产生闭包呢?

那么再思考一个点,如果在外部函数内部有两个函数,其中一个函数有使用外部变量,而另外一个没有使用。未使用的函数,是否还有闭包呢?

 //闭包function closure_Fn() {var num = 1;function add() {debugger }function list(){return num}add()}closure_Fn() 

我们发现,即使add函数内部没有任何外部变量的引用,但是因为其他函数引用了。我们在调用该函数的时候,仍然存在闭包。

我们再看看一些其他的情况:

const name='test'

export default function(){return name
}

let fun
if(true){let num=0function add(){console.log(mum++)}fun=add
}

fun() 

以上两种情况算闭包?答案是否定的,这两种状况分别为moduel scopeblock state,这些内容我将在以后介绍。也可以作为当前的扩展阅读,大家先去查看一下。

面试实战

何为闭包

闭包产生于函数嵌套的场景,内部函数引用了外部函数作用域的变量。只要其中一个函数形成了闭包,其他函数都有该函数变量。非函数嵌套的形式,不是闭包。无论函数是否返回函数,都视为一个闭包。

在tree shanking情况下,闭包会被如何编译?

以下为例

 function outer() {let x = 1;return function inner() {return x;};
}

document.body.appendChild(outer()); 

可以看到,webpack很聪明的跳过了复杂的闭包,直接展示了结果。 所以一些看似复杂的闭包,编译器是可以理解和优化的。

模块化情况下,非函数嵌套是否存在闭包?

根据上文,这个问题是否定的,变量存在模块作用域里,而不是闭包作用域

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值