闭包
概述:闭包是一种书写代码一种结构,这种结构拥有的特性就是内部的空间在使用中不会被回收。(内部的变量以及对应的参数不会被gc回收)
函数的预编译过程
- 开辟函数的内存空间
- 开辟一个代码的对应的内存空间。
- 将对应的代码块的引用放入这个函数的内存空间
函数的执行过程
- 开辟一个执行空间(执行栈)
- 将对应的函数的里面的代码块内容的放到方法执行栈中进行执行
- 执行完 对应的执行空间销毁了 那么对应的里面的代码块内容也就销毁(gc 回收)
函数的示例
function reduce(){
var i = 0
i++
}
reduce() //1
reduce() //1
//因为里面的i执行完以后就会销毁 那么对应每次创建的i这个变量都是一个新的变量
- 通过上述的示例代码,我们知道对应的每次执行函数,里面的变量或者参数都会重新声明,这个也就意味着每次里面的变量或参数都是一个新的变量,这个时候有些情况我们就不满足。那么如果我想让他里面的变量不回收,是不是需要有个内容给他保持引用,我的变量就不会被gc 回收。
- 根据上述讲解 我们就可以得到 为什么i为全局变量的时候 俩次的值不一样
var i = 0
function reduce(){
i++
}
reduce() //1
reduce() //2
// 因为i保持对应的引用 所以没有被回收
- 那么根据上述可得 如果我在函数内返回对应的一个引用,在这个引用内包含对i的引用 那么i 是不是也不会被回收。
function reduce(){
var i = 0
i++
retrun {
i
}
}
let obj = reduce()
console.log(obj.i)//1
obj.i++
console.log(obj.i)//2
- 根据上述代码 就是如果我的函数里面返回一个引用 这个引用内包含了对应外部函数的参数或变量,那么我的这个外部函数的参数他不会随着函数里面代码的块的销毁而销毁。那么我同时又知道函数也是引用数据类型,那么我们是不是可以直接返回函数(方便调用)。内部函数包含外部函数的变量 这个时候对应的变量也不会被销毁了。
function reduce(){
var i = 0
return function(){
i++
return i
}
}
//调用
let fn = reduce()
console.log(fn()) //1
console.log(fn()) //2
函数嵌套函数(返回函数),内部函数保持对应外部函数的变量(参数)的引用。 这个称为闭包(外部的变量不会被gc回收)。
闭包的特性
- 可以通过内部函数引用 ,在调用内部函数的过程中访问外部函数的变量。
- 外部函数的参数不会被gc 回收
- 内部函数时刻保持对应外部函数的引用
闭包的优点
- 不会被gc回收
- 扩大外部函数内变量的使用范围
- 避免函数内的变量被外部所污染
闭包的缺点
- 导致内存泄漏(内存溢出) 消耗内存
- 内部函数要时刻保持对应外部函数的引用
闭包的运用
- 作为缓存
- 防抖 节流
- 函数柯里化
防抖
概述:在规定时间内只执行一次(执行最后一次)
电梯关门案例
- a 进入电梯 等待5s后 就可以上升了
- 在a等待了4s中后 b过来 那么之前的等待就结束了 开始新的等待
- 在b等待了3s后 c过来 那么之前的等待也结束了 开始新的等待
- .... 直到最后一次等待结束 电梯就上升 (实际电梯上升这个操作 只执行一次 是最后一次)
防抖的实现
//执行的