带你彻底看透——闭包
前言
在弄懂闭包之前,我们最好能掌握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。
执行过程如下四张图所示:
执行完毕后,该函数的执行上下文对象就会被销毁,也就是出栈,紧接着,全局执行上下文对象也会出栈。
二、闭包
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的值了。调用栈如下图所示:
3、闭包的缺点
闭包也存在着缺点,一旦形成闭包,只有在页面关闭后,闭包占用的内存才会被回收,所以造成了内存泄漏
4、闭包的作用
1)模块化开发(实现公有变量)
2)做缓存
3)封装私有化属性
4)防止全局变量污染
最后
以上就是闭包的介绍,看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~
文章可能有一些错误,欢迎评论指出,也欢迎一起讨论。