什么是执行上下文?
js代码解析执行时所处的环境,顾名思义。
全局执行上下文
只有一个,浏览器中全局对象就是window对象,this指向全局对象
函数执行上下文
只有函数被调用时才会创建执行环境,可以有多个,多次。
eval执行上下文
js中不推荐用这个函数
执行栈
栈的结构,后进先出。先会创建一个全局的执行上下文,push到当前的执行栈顶,当调用新的函数则push新的函数执行上下文,当执行完后pop出执行栈。
执行上下文的创建过程
两个阶段创建阶段和执行阶段
创建阶段
确定this指向
全局执行上下文中,this指向全局
函数执行上下文中,this指向取决于当前调用的方式。
创建词法环境
词法环境有两个组成部分
环境记录是存储变量和函数声明的实际位置。
对外部环境的引用意味着它可以访问其外部词法环境。
词法环境有两种类型
全局环境是一个没有外部环境的词法环境,外部环境应用为null。拥有一个全局对象以及该对象拥有的对象和属性,还有用户自定义的全局变量。
函数环境,包括用户在函数定义的变量存储在环境记录中,包括argumnets对象。外部环境可能是全局环境,也可能是包含内部函数的外部函数环境。
GlobalExectionContext = { // 全局执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Object", // 全局环境
// 标识符绑定在这里
outer: <null> // 对外部环境的引用
}
}
FunctionExectionContext = { // 函数执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Declarative", // 函数环境
// 标识符绑定在这里 // 对外部环境的引用
outer: <Global or outer function environment reference>
}
}
创建变量环境
变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性。
在 ES6 中,词法环境和变量环境的区别在于前者用于存储函数声明和变量( let 和 const )绑定,而后者仅用于存储变量( var )绑定。
变量提升的原因
在创建阶段,函数声明存储在环境中,而变量会被设置为 undefined(在 var 的情况下)或保持未初始化(在 let 和 const 的情况下)
执行阶段
进入执行上下文
添加形参,变量声明,函数声明,
同一作用域下,函数提升比变量提升得更靠前.
代码执行
修改变量对象的值
内存回收和内存泄露
标记清除(常用)
标记清除算法将“不再使用的对象”定义为“无法到达的对象”。即从根部(在JS中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,保留。那些从根部出发无法触及到的对象被标记为不再使用,稍后进行回收。
ES6 新出的两种数据结构:WeakSet 和 WeakMap,表示这是弱引用,它们对于值的引用都是不计入垃圾回收机制的。
常见的内存泄露
内存机制
基本类型:--> 栈内存(不包含闭包中的变量)
引用类型:--> 堆内存