likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 36

快速阅读

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

何为三板斧

目前看了近期的一些面经,发现前端面试的高频三板斧:闭包,事件循环,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面板打印出

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

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

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

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

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

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

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

前端面经高频手撕-js面试三板斧-闭包(1)-- 初识闭包 看到还是有的,所以我们可以看到无论是否return,只要在函数内调用外部函数作用域内的变量,就会产生闭包。

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

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

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

我们发现,即使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 scopeblock state,这些内容我将在以后介绍。也可以作为当前的扩展阅读,大家先去查看一下。

面试实战

何为闭包

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

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

以下为例


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


document.body.appendChild(outer());

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

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

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

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

转载自:https://juejin.cn/post/7176223289222627384
评论
请登录