目录
- 前言
- 阐述闭包是什么?
- 函数的创建和执行看闭包(引述:堆栈、EC、AO、VO、scope)
- 闭包的作用以及在项目中的引用场景,以及带来的问题
- 闭包引发的高级编程技巧,在框架源码中的使用,或者自己写类库的怎么使用的
- 结束语
- 题外话
前言
不管是初级、中级的前端面试中,还是高级的前端面试中,闭包这个问题都会被拿来考验面试者。不同能力的面试者对这个问题的回答也是差别比较大的,
常见的面试问答,有如下几种场景。青铜面试者
闭包是xx…。它的危害xx…。钻石面试者
闭包是xx…。它的特点是xx…,它的危害xx…。我们日常怎么使用xx…。
这两类的面试者是非常常见的,不能说回答的不好,但是回答的也不能算惊艳,哪如何回答好闭包的问题了,往下看。
1. 阐述闭包是什么?
- 官方说法:闭包就是指有权访问另一个函数作用域中的变量的函数。
- MDN 说法:闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。 环境由闭包创建时在作用域中的任何局部变量组成。
- 自我理解:把函数执行,形成私有上下文,并且保存和保护私有变量的机制,称之为“闭包” ,它是一种机制。
2. 函数的创建和执行看闭包(引述:堆栈、EC、AO、VO、scope)
浏览器在加载页面会把代码放在栈内存( ECStack )中执行,函数进栈执行会产生一个私有上下文( EC ),此上下文能保护里面的使用变量( AO )不受外界干扰,并且如果当前执行上下文中的某些内容,被上下文以外的内容占用,当前上下文不会出栈释放,这样可以保存里面的变量和变量值,所以我认为闭包是一种保存和保护内部私有变量的机制。
函数创建
- 创建一个堆:储存代码字符串和对应的键值对。
- 初始化当前函数的作用域:[[ scope ]] = 所在上下文EC中的变量对象 VO / AO。
函数执行
- 形成私有上下文,函数每一次执行 都是从新形成一个全新的私有上下文,和之前执行产生的上下文没有必然的联系。
- 进栈执行
- 创建 AO
- 初始化作用域链[[ scopechain ]]:< EC < FN >, 作用域< ECXXX >>或者也可以这样理解< AO, VO(G) >
- 初始化 this
- 初始化 arguments
- 形参赋值
- 变量提升
- 代码执行
- 遇到变量就先看是否是自己私有的,不是自己私有的按照作用域链上查找,如果不是上级的就继续线上查找,,直到 EC(G),变量的查找其实就是一个作用域链的拼接过程,拼接查询的链式就是作用域链。
正常情况下,代码执行完成之后,会有三类情况。
- 当前上下文的某些东西被上下文以外的某些东西占用,那么当前上下文就不会被释放,就形成了闭包。
- 如果没有被占用就是执行完成之后就被释放,不会形成闭包。
- 除了这上面两种情况还有一种情况是,上下文没有被占用,但是要紧接着被用一次,这样没有用完之前是不能释放的,用完在释放,这样就形成了一个临时不被释放闭包。
3. 闭包的作用以及在项目中的引用场景,以及带来的问题
函数执行会形成全新的私有上下文,这个上下文可能被释放,也可能不被释放,不论是否被释放,它的作用是:
- 保护:划分一个独立的代码执行区域,在这个区域中有自己私有变量存储的空间,而用到的私有变量和其它区域中的变量不会有任何的冲突(防止全局变量污染)
- 保存:如果上下文不被销毁,那么存储的私有变量的值也不会被销毁,可以被其下级上下文中调取使用
在实际的项目中,会基于闭包把自己编写的模块内容包裹起来,这样编写就可以保护自己的代码是私有的,防止和全局变量或者是其他的代码冲突,这一点是利用保护机制。
在没有使用 ES6 的 let 之前,我们循环处理事件绑定,在事件触发需要用到引所值的时候,我们基于闭包,把每一轮循环的引所值保存起来,这样来实现我们的需求。只不过现在基于let会产生块级作用域来保护需要保存的内容(机制类似于闭包)。
但是不建议过多的使用闭包,因为使用不被释放的上下文,是占用栈内存空间的,过多的使用会导致渲染页面变慢,所以要合理的使用闭包。
4. 闭包引发的高级编程技巧,在框架源码中的使用,或者自己写类库的怎么使用的
除了在这些传统的业务开发中会引用闭包,我之前在研究别人的源码和自己写一些插件的时候,往往会利用一些JS高阶编程技巧俩是吸纳代码的管理和功能的开发,他们的机制都是使用闭包,例如:惰性函数、柯里化函数、compose函数。
从上面这几个大的方面来回答闭包是一个不错的角度,理论、底层运行机制、实践,不仅能看出你基础能力的深度,也能看出你基础能力的广度。
结束语
如果文章中什么不对或者写的不好的地方,请大家多多指正,谢谢!码字不易,点个赞加个关注吧!
题外话
笔者在「深圳虾皮」,一家口碑还不错的东南亚电商公司,2021大量招人,机会多多!快来加入我们吧!
现在有想法,还是以后有想法的同学,都可以加我微信[stone—-999]!内推你加入我们的大家庭!