前端面经高频手撕-js面试三板斧-闭包(1)-- 初识闭包
快速阅读
如果你已经很了解闭包,那么可以直接跳到最后的们面试实战
环节!~
何为三板斧
目前看了近期的一些面经,发现前端面试的高频三板斧:闭包,事件循环,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() {
debugger
return ++num;
}
add()
}
closure_Fn()
这段代码与刚才的不同,是没有return函数进行调用,而是直接执行了,那么在这种情况下,是否会产生闭包呢?
看到还是有的,所以我们可以看到无论是否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=0
function add(){
console.log(mum++)
}
fun=add
}
fun()
以上两种情况算闭包?答案是否定的,这两种状况分别为moduel scope
和block state
,这些内容我将在以后介绍。也可以作为当前的扩展阅读,大家先去查看一下。
面试实战
何为闭包
闭包产生于函数嵌套的场景,内部函数引用了外部函数作用域的变量。只要其中一个函数形成了闭包,其他函数都有该函数变量。非函数嵌套的形式,不是闭包。无论函数是否返回函数,都视为一个闭包。
在tree shanking情况下,闭包会被如何编译?
以下为例
function outer() {
let x = 1;
return function inner() {
return x;
};
}
document.body.appendChild(outer());
可以看到,webpack很聪明的跳过了复杂的闭包,直接展示了结果。 所以一些看似复杂的闭包,编译器是可以理解和优化的。
模块化情况下,非函数嵌套是否存在闭包?
根据上文,这个问题是否定的,变量存在模块作用域里,而不是闭包作用域
转载自:https://juejin.cn/post/7176223289222627384