JavaScript 执行上下文

162 阅读3分钟

什么是执行上下文

执行上下文是用来描述的 JavaScript 执行的环境的抽象概念,记录了代码在执行中的信息,一般有一下几种类型:

  • 全局执行上下文
  • 函数执行上下文
  • eval 执行上下文

执行栈

用来管理执行上下文的工具,一个 后进先出 的调用栈,在程序开始时,会先出现一个 全局执行上下文 ,后每次调用函数,都会生成一个 函数执行上下文 并压栈,函数执行完成后,退栈并被 GC 回收,下面用一个案例来讲解

var name = 'xiaoming';

function person() {
    function people() {
        console.log(name);
    }
    
    people();
}

person();

下面逐步讲解上述例子中执行上下文的创建和回收

创建
  1. 在开始执行代码时,创建全局执行上下文并压栈,初始化全局变量 name 和全局方法 person
  2. 调用 person 方法,创建 person 函数执行上下文并压栈,初始化 people 方法
  3. 调用 people 方法,创建 people 函数执行上下文并压栈,初始化 console 方法
  4. 调用 console 方法,创建 console 函数执行上下文并压栈

image.png

回收

每次调用完毕就会依次从最顶层开始退栈,并被 GC 回收,与创建过程相反,这里就不赘述了,具体如下图

image.png

执行上下文的创建

执行上下文的创建主要做这两个事情

  • 创建词法环境组件:指定一个词法环境对象,用于解析该执行环境内的代码创建的标识符引用。
  • 创建变量环境组件:指定一个词法环境对象,其环境数据用于保存由该执行环境内的代码通过 VariableStatement 和 FunctionDeclaration 创建的绑定。
  • this 绑定:指定该执行环境内的 ECMA 脚本代码中 this 关键字所关联的值。

词法环境可以参另一篇文章《JavaScript 词法环境》

变量环境(VariableEnvironment)

变量环境组件组件与词法环境组建同为词法环境对象,区别于变量环境只存储 var function 声明的变量

var 与 let 和 const

  • 提前激活

通过 let/const 声明的变量在初始化时是 <uninitialized>,在未声明时调用会得到 Uncaught ReferenceErro,又称 暂时性死区
而通过 var 声明的变量在初始化时会被提前声明并赋值 undefined

console.log(name); // Uncaught ReferenceErro
let name = 'xiaoming';
// -----
console.log(name); // undefined
var name = 'xiaoming';
  • 作用域

另一个最大的区别就是 let/const 属于 块级作用域。在 BlockCaseBlock 时会创建一个 块级作用域,在里面通过 let/const 声明的变量会与这个作用域强绑定,简单来说就是不能被外部所获取,而 var 则不受此限制

if (true) {
    var name = 'xiaoming';
    let age = 18;
}
console.log(name); // xiaoming
console.log(age); // age is not defined

如果上面所说的你都已经完全理解,相信下面这段代码也难不倒你

var name = 'xiaoming';
function sayName() {
    console.log(age);
    if (name === 'xiaoming') {
        var age = 'xiaodong'
        console.log(name);
        let name = 'xiaodong';
    }  
}
sayName();

提前激活

提前激活 也可以称为 变量提升 ,如上面我们知道通过 var 声明的变量会在编译时就被提前初始化并设置为 undefined
这得益于 JavaScript 在词法解析阶段会生成 全局上下文 函数上下文,并初始化赋值

image.png

总结

执行上下文 创建 -> 执行 -> 回收 过程简单总结

  1. 创建全局上下文的词法环境,声明式环境记录,对象环境记录
  2. outer 指向 null
  3. 创建全局上下文的变量环境,过程如上
  4. this 指向,window
  5. 创建函数上下文的词法环境,如全局上下文
  6. outer 指向,根据实际可能为 全局上下文/父词法环境
  7. this 指向
  8. 进入函数执行阶段
  9. 函数执行完后 GC 回收

重新学习,如发现错漏地方,欢迎更正,共勉