执行上下文

执行上下文是对 JavaScript 代码执行环境的概念抽象,只要有js代码运行,它就一定运行在执行上下文中

执行上下文分为三种

  • 全局执行上下文:也就是浏览器的全局对象 window
  • 函数执行上下文:每次函数被调用时都会(才会)创建一个新的执行上下文
  • Eval执行上下文:运行在 Eval 函数中的代码, 很少用且不建议使用

可以有任意多个函数上下文,每次调用函数创建一个新的上下文,会创建一个私有作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问

执行上下文的生命周期:创建、执行 和 回收

创建阶段:函数被 调用 ,但 执行之前

  1. 确定 this 的值,也被成为 This Binding
  2. LexicalEnvironment(词法环境) 组件被创建
    词法环境由两个部分组成:
    1. 全局环境:是一个没有外部环境的词法环境,外部引用环境为 null ,有一个全局对象,this 就指向这个全局对象
    2. 函数环境:用户在函数中定义的变量被存储在环境记录中,包含了 arguments 对象,外部环境的引用可以是全局环境,也可以是包含内部函数的外部函数环境
  3. VariableEnvironment(变量环境) 组件被创建 
    变量环境也是一个词法环境,因此它具有上面定义的词法环境的所有属性在 ES6 中,词法环境和变量环境的区别在于前者用于存储函数声明和变量(let和 const )绑定,而后者仅用于存储变量(var)绑定
// 执行上下文 伪代码
GlobalExceptionContext = {
    LexicalEnvironment: {
        EnvironmentRecords: {
            Type: "Object",
            outer: "null"
        }
    }
}

FunctionExceptionContext = {
    LexicalEnvironment: {
        EnvironmentRecords: {
            Type: "Declarative",
            outer: "Global or outer function Environment reference"
        }
    }
}
// 示例代码
let a = 20;
const b = 30;
var c;

function multiplay(e, f) {
    var g = 20;
    return e * f * g;
}

c = multiplay(a, b)

// 执行过程
GlobalExectionContext = {
    ThisBinding: "Global Object",
    LexicalEnvironment: { //
        EnvironmentRecord: {
            Type: "Object",
            a: "uninitialized",
            b: "uninitialized",
            multiply: "func"
        },
        outer: "null"
    },
    VariableEnvironment: { //
        EnvironmentRecord: {
            Type: "Object",
            c: undefined,
        },
        outer: "null"
    }
}

FunctionExceptionContext = {
    ThisBinding: "Global Object",

    LexicalEnvironment: {
        EnvironmentRecords: {
            Type: "Declarative",
            Arguments: {0: 20, 1: 30, length: 2}
        },
        outer: "GlobalLexicalEnvironment",
    },

    VariableEnvironment: {
        EnvironmentRecords: {
            Type: "Declarative",
            g: undefined,
        },
        outer: "GlobalLexicalEnvironment",
    }
}

let 和 const 定义的变量 a和 b 在创建阶段没有被赋值,但 var 声明的变量从在创建阶段被赋值为 undefined

这是因为,创建阶段,会在代码中扫描变量和函数声明,然后将函数声明存储在环境中但变量会被初始化为 undefined(var 声明的情况下)和保持 uninitialized(未初始化状态)(使用 let 和 const 声明的情况下)
这就是变量提升的实际原因

执行阶段:执行变量赋值、执行代码

如果 Javascript 引擎在源代码中声明的实际位置找不到变量的值,那么将为其分配 undefined

回收阶段:执行上下文出栈 等待 虚拟机回收 执行上下文

执行栈

执行栈也叫调用栈,具有LIFO(后进先出)的数据结构,用于存储在代码执行期间创建的所有执行上下文

当 Javascript 引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中

每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文

posted on 2024-09-16 17:01  XiSoil  阅读(3)  评论(0编辑  收藏  举报