一文理解javaScript执行上下文,调用栈结构

我们先概括他的概念:词法环境:就是编译阶段记录函数声明,变量声明,函数的声明的形参的合集。
词法环境由两部分组成:环境记录器(Environment Record)对外部环境的引用(outer)
环境记录器就是变量集合。
outer 就是指向父级词法环境的指针。

执行上下文 context

  • lexical environment:词法环境,当获取变量时使用
  • variable environment:变量环境,当声明变量时使用
  • this value: this 值

词法环境 和 变量环境

变量环境组件(VariableEnvironment component ) 用来登记 varfunction 等变量声明

词法环境组件(LexicalEnvironment component ) 用来登记 letconstclass 等变量声明
变量环境只有全局和函数作用域词法环境则是有全局、块、函数

  • 词法环境:包括所有声明的标识符(如 let, const, 函数声明等)及其值,以及与当前执行上下文相关的父级作用域链。词法环境的主要目标是跟踪变量、函数和块级作用域的绑定。
  • 变量环境:主要关注的是 变量声明(特别是 var 声明)。它专门处理如何存储、提升和管理变量。在某些情况下,变量环境和词法环境看起来很相似,但它更多地关注 var 声明,尤其是在函数作用域中。

我们来举个小案例:

function foo(){
    var a = 1
    let b = 3
    {
      let b = 3
      var c = 4
      let d = 5
      console.log(a)
      console.log(b)
    }
    console.log(b) 
    console.log(c)
    console.log(d)
}   
foo()

首先会进行编译,将foo中的所有var关键字声明的变量存储到变量环境中

在这里插入图片描述

接着开始执行代码
执行函数内代码块外的代码:
词法环境是一个栈型结构
在这里插入图片描述

执行代码块内的代码:
在这里插入图片描述

当执行 console.log(a) 这条代码时的查找路径是这样的
在这里插入图片描述

执行栈(调用栈)

编译阶段:我们会往调用栈里压入全局执行上下文。再创建全局的词法环境
执行阶段:遇到函数,创建一个函数执行上下文,再创建函数的词法环境,当该函数执行完后,从调用栈中弹出。到最后调用栈中只剩一个全局执行上下文,除非你关闭浏览器,不然全局执行上下文不会弹出

JavaScript 引擎是按照可执行代码来执行代码的,每次执行步骤如下:

  1. 创建一个新的执行上下文(Execution Context)
  2. 创建一个新的词法环境(Lexical Environment)
  3. 把 LexicalEnvironment 和 VariableEnvironment 指向新创建的词法环境
  4. 把这个执行上下文压入执行栈并成为正在运行的执行上下文
  5. 执行代码
  6. 执行结束后,把这个执行上下文弹出执行栈

举个例子,假如我们的代码是下面这样

var a = 1;

function foo() {
}

function baz() {
    foo();
}

baz();

那么我们的栈结构是如下图

在这里插入图片描述

  • 在任何代码执行之前,先创建全局执行上下文,并往调用栈中压栈(编译阶段)
  • 创建词法环境,登记函数声明和变量声明(编译阶段)
  • 引擎执行到 baz() ,创建 baz() 的函数执行上下文,并往调用栈中压栈
  • 函数 baz() 调用 foo() ,创建 foo() 执行上下文,并将其压入调用栈中
  • 函数 foo() 也执行完毕,弹出调用栈
  • 函数 baz() 同样执行完毕,弹出调用栈
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值