深入浅出执行上下文、词法环境、变量环境

2020-11-20  本文已影响0人  灯下草虫鸣314

执行上下文的概念

执行上下文:javascript 代码解析和执行时所在的环境。

执行上下文的类型

执行上下文分为三种类型:

1.全局执行上下文

2.函数执行上下文

3.Eval执行上下文

执行上下文栈

执行上下文栈是一个后进先出的数据结构,
具体执行流程如下

如以下函数执行时的执行栈变化为:

function fun1(){
    console.log('func1')
    fun2()
}
function fun2(){
    console.log('func2')
}
fun1()  
/*
*                     fun2
*           fun1      fun1       fun1   
* global => global => global => global => global
*/

执行上下文生命周期

变量对象VO和活动对象AO

在讲生命周期钱。我们必须了解讲个对象,变量对象VO和活动对象AO

变量对象VO:

创建阶段

此阶段执行上下文会执行以下操作

执行阶段

举例说明

function a(name, age){
    var a = 1
    function c(){}
    var d = funciton (){}
    (function e(){})
    var f = function g(){}
}
a('John')
// 如上代码。
//在创建预编译阶段生成的AO对象如下
AO = {
    arguments:{
        0: 'John',
        1: undefined,
        length: 2
    },
    name: 'John',
    age: undefined,
    c: reference to function c(){},
    a: undefined,
    d: undefined,
    f: undefined,
}
// 函数表达式 e,不在AO中 
// 函数g不在AO中

// 函数执行时AO对象如下
AO = {
    arguments:{
        0: 'John',
        1: undefined,
        length: 2
    },
    name: 'John',
    age: undefined,
    c: reference to function c(){},
    a: 1,
    d: reference to FunctionExpression "d",
    f: reference to FunctionExpression "f",
}

函数声明提前

从AO对象的创建过程我们就可以发现,AO对象想是先扫描函数体内的函数声明才去扫描变量声明。所以这也就是为啥会有声明提前。

变量提升

AO对象创建时已经将函数内部的变量提前扫描声明。是指在函数执行的过程中开始依次赋值。

词法环境和变量环境

在ES6中提出词法环境和变量环境两个概念。主要是执行上下文创建过程。

词法环境(LexicalEnvironment)

词法环境是一种包含 标识符 => 变量 隐射关系的一种结构。

在词法环境中有两个组成部分:

词法环境分为两种类型:

举例词法环境在伪代码中如下:

GlobalExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 剩余标识符
    },
    Outer: null,
  }
}

FunctionExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 剩余标识符
    },
    Outer: [Global or outer function environment reference],
  }
}

变量环境(VariableEnvironment)

变量环境也是一个词法环境。他具有词法环境中所有的属性
在ES6中,LexicalEnvironment和VariableEnvironment 的区别在于前者用于存储函数声明和变量let 和 const 绑定,而后者仅用于存储变量 var 绑定。

用以下代码举例:

let a = 20;  
const b = 30;  
var c;

function add(e, f) {  
 var g = 20;  
 function c(){}
 return e + f + g;  
}

c = add(20, 30);

在预编译阶段。生成的词法环境和变量环境如下

GlobalExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      a: <uninitialied>,
      b: <uninitialied>,
      add: <func>
      // 剩余标识符
    },
    Outer: null,
  },

  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      c: undefined,
      // 剩余标识符
    },
    Outer: null,
  }
}

FunctionExectionContent = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      arguments: {
        0: 20,
        1: 30,
        length: 2,
      },
      e: 20,
      f: 30,
      c: reference to function c(){}
      // 剩余标识符
    },
    Outer: GlobalLexicalEnvironment,
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      g: undefined,
      // 剩余标识符
    },
    Outer: GlobalLexicalEnvironment,
  }
}

我们发现使用let和const声明的变量在词法环境创建时是未赋值初始值。而使用var定义的变量在变量环境创建时赋值为undefined。这也就是为什么const、let声明的变量在声明钱调用会报错,而var声明的变量不会。

代码执行阶段

此阶段的执行流程就是函数执行时的流程。给变量赋值,和执行其他逻辑代码。

上一篇下一篇

猜你喜欢

热点阅读