闭包
每当我们运行代码的时候,代码就会生成执行上下文(可以理解为执行环境)
JavaScript执行环境主要分为三种:
- 全局环境
- 函数环境
- Eval环境
JavaScript用栈处理多个执行上下文
作用域链
创建执行上下文分两个阶段
创建阶段
- 作用域链
- 包含当前变量对象+所有父级变量对象
- 变量对象(参数、变量函数声明)
- this
执行阶段
- 变量赋值、函数引用等
1 | function books(){ |
上面代码的上下文创建顺序
全局执行上下文 = {作用域链:{全局变量对象}, {变量对象: books, bag}}
books执行上下文 = {作用域链:{books变量对象+全局变量对象},{变量对象:book}}
匿名函数执行上下文 = {作用域链:{匿名函数遍历对象+books变量对象+全局变量对象},{变量对象:}}
一道题:
1 | for(var i = 0;i<5;i++){ |
解析:
顺序是这样的,1. 循环走完 设置完一堆定时器 定时器里的函数并没有执行;2. 执行第6条的log输出第一个5;3. 定时器时间到,开始执行,此时i从5开始计算 输出 5,6,7,8,9;
闭包的应用-数据私有
没有使用闭包
1 | let i = 0; |
我们希望i这个变量是私有的,脱离全局上下文环境
1 | function count(){ |
这样子i就不在全局上下文环境中了,不会被全局上下文中的代码修改掉。
闭包内存泄露
1 | function count(){ |
- fun是一个全局变量,代码执行完毕不会立即销毁
- fun使用count函数
- count函数使用fn函数
- fn函数里面有用到i
- i被引用就不会被回收,所以一直存在
此时:闭包引起了内存泄漏
不是所有的内存泄露都要手动回收的
比如react里面很多闭包不能回收的
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 学途路漫漫!