字节面试——带你彻底看透闭包

487 阅读3分钟

带你彻底看透——闭包

前言

在弄懂闭包之前,我们最好能掌握js预编译作用域以及作用域链这些基础知识,如果大家对这些仍有些模糊,可以看看我的上一篇文章:轻松get——js预编译,作用域以及作用域链 - 掘金 (juejin.cn),希望能让你更好的理解闭包

正文

开始聊闭包之前,我们还需要知道调用栈的概念。

一、调用栈

定义:调用栈是用来管理函数调用关系的一种数据结构

当一个函数执行完毕,该函数的执行上下文就会被销毁出栈)。

举个例子:

var a=2
function add(){
    var b=10
    return a+b
}
add()

下面我们用画图的方式来描绘这个例子:

第一步,全局的代码进行预编译,会创建一个全局执行上下文对象GO,进栈
第二步,全局的代码执行,a赋值为2,add函数调用。
第三步,add函数的调用带来了add函数预编译,会创建一个add函数的执行上下文对象AO,进栈
第四步,add函数执行,b赋值为10,返回a+b。

执行过程如下四张图所示:

image.png image.png image.png image.png

执行完毕后,该函数执行上下文对象就会被销毁,也就是出栈,紧接着,全局执行上下文对象也会出栈。

二、闭包

1、闭包的形成

来看一个例子:

function a(){
    function b(){
        var bbb=234
        console.log(aaa);  //打印结果:123
    }
    var aaa=123
    return b
}
var demo=a()
demo()

在没学习闭包之前,我们大多数会这么想:

首先进行全局预编译,之后全局代码执行,函数a调用赋给demo,demo的调用等同于函数b的调用,函数b在打印aaa时在b函数作用域内并没有找到aaa的值,故去全局作用域找,全局作用域也没有aaa的值,这个时候,我们想,得到的打印结果应该是undefined

但是最终的打印结果却是123!

原因:这里形成了闭包

闭包的形成:当函数a内部函数b返回出来调用

2、闭包的定义

闭包的定义:当通过调用 外部函数返回内部函数 后,即使外部函数已经执行结束了,但是内部函数引用了外部函数的变量依然会被保存在内存中,我们把这些变量的集合称为闭包。

做个比喻,闭包就可以把它比作一个背包,背包中存放的就是内部函数引用外部函数的变量。

这样就可以解释上面的例子啦!在函数a执行完后,函数a的执行上下文对象不会被回收,内部函数b引用的外部函数a的的变量依然会被保存在内存中,这样就能访问到aaa的值了。调用栈如下图所示:

image.png

3、闭包的缺点

闭包也存在着缺点,一旦形成闭包,只有在页面关闭后,闭包占用内存才会被回收,所以造成了内存泄漏

4、闭包的作用

1)模块化开发(实现公有变量)
2)做缓存
3)封装私有化属性
4)防止全局变量污染

最后

以上就是闭包的介绍,看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~
文章可能有一些错误,欢迎评论指出,也欢迎一起讨论。