闭包的形成
浅层次(现象)
函数存在嵌套关系,内层函数可以访问外层函数变量。这就是形成了闭包
深层次(实质)
实际上,闭包跟作用域离不开,因为父函数的作用域,子函数也能访问到(依据作用域链),所以存在上级作用域的引用
作用域和作用域链
作用域:当函数执行前期,会创建一个执行期上下文的内部对象,A0(作用域)
这个内部对象,是预编译的时候,创建出来的。因为函数被调用的时候,会进行预编译
在全局代码执行前期,会创建出一个执行期上下文的AO对象
作用域链:AO和GO的集合
闭包的应用
大多数是在维护内部变量
1. 将对变量(状态)的变化封装在安全的环境中(保存this,节流防抖)
2. 将代码封装成一个闭包形式,等待时机成熟的时候再使用,比如实现柯里化和反柯里化
比如平时需要写一些防抖,节流函数。就需要维护内部变量,会用到闭包。
再比如函数存在嵌套关系,想要保存当前this,给嵌套的函数使用,也会用到闭包。
还有函数柯里化,也会用到闭包
说出这些应用,此时你就是占据主导地位了,为什么这么说?
你把闭包的应用说了这个多,
那坏处是什么?你说内存泄漏,那常见的内存泄漏有哪些?怎么避免?如何主动发现内存泄漏?
你说节流,防抖。那节流防抖,概念您能说说吗?项目中在哪里用到节流防抖?你能手写一个节流,防抖吗?
你说嵌套函数,想要保存当前this,那还有其他方法吗?你说了箭头函数,那普通函数和箭头函数,有什么区别?
你说柯里化,那什么是柯里化呢?柯里化实现的应用有哪些? 能手写一个柯里化吗?
接着来说闭包的使用场景
单独输出文章
使用闭包有啥问题
内存泄漏: 不再用到的内存,没有得到及时的释放
为什么闭包会引起内存泄漏呢?
因为函数存在嵌套关系, 父函数作用域里的AO环境,子函数也能访问到。当父函数执行完毕,作用域销毁。
但是子函数还引用着父函数的变量,所以父函数的变量不会销毁,如果得不到释放,他就是垃圾了
为什么基本类型放在栈内存中
因为这个作用域里包含了所有在该函数中声明变量,所以变量(基本数据类型)存储在栈中
那就来说说栈和堆
栈: 栈内存线性有序存储,容量小,系统分配效率高
堆:堆内存首先要在堆内存新分配存储空间,之后又要把指针存储在栈内存中,效率相对低一些
栈内存,基本上用完就被回收了,而堆内存中变量,因为有很多不确定的引用,只有当调用的变量,全部销毁,才能回收
所以JavaScript引擎需要用栈来维护程序执行期间的上下文的状态,
如果栈空间大了的话,所有数据都存放在栈空间里面,会影响到上下文切换的效率,进而影响整个程序的执行效率。