每当我们运行代码的时候,代码就会生成执行上下文(可以理解为执行环境)
JavaScript执行环境主要分为三种:
- 全局环境
- 函数环境
- Eval环境
JavaScript用栈处理多个执行上下文

作用域链
创建执行上下文分两个阶段
-
创建阶段
-
- 作用域链
-
-
- 包含当前变量对象+所有父级变量对象
-
-
- 变量对象(参数、变量函数声明)
- this
-
执行阶段
-
- 变量赋值、函数引用等
function books(){
var book = "书包里面的书本"
return function(){
console.log(book);
}
}
var bag = books();
bag()
上面代码的上下文创建顺序
全局执行上下文 = {作用域链:{全局变量对象}, {变量对象: books, bag}}
books执行上下文 = {作用域链:{books变量对象+全局变量对象},{变量对象:book}}
匿名函数执行上下文 = {作用域链:{匿名函数遍历对象+books变量对象+全局变量对象},{变量对象:}}
一道题:
for(var i = 0;i<5;i++){
setTimeout(function(){
console.log(i++);
},4000)
}
console.log(i);//556789
解析:
顺序是这样的,1. 循环走完 设置完一堆定时器 定时器里的函数并没有执行;2. 执行第6条的log输出第一个5;3. 定时器时间到,开始执行,此时i从5开始计算 输出 5,6,7,8,9;
闭包的应用-数据私有
没有使用闭包
let i = 0;
function fn(){
i++
console.log(i);
}
//另外一个程序
i= 1000
fn()//1001
我们希望i这个变量是私有的,脱离全局上下文环境
function count(){
let i = 0;
function fn(){
i++
console.log(i);
}
return fn
}
i = 1000
const fun = count()
fun()//1
这样子i就不在全局上下文环境中了,不会被全局上下文中的代码修改掉。
闭包内存泄露
function count(){
let i = 0;
function fn(){
i++
console.log(i);
}
return fn
}
const fun = count()
- fun是一个全局变量,代码执行完毕不会立即销毁
- fun使用count函数
- count函数使用fn函数
- fn函数里面有用到i
- i被引用就不会被回收,所以一直存在
此时:闭包引起了内存泄漏
不是所有的内存泄露都要手动回收的
比如react里面很多闭包不能回收的
