Code前端首页关于Code前端联系我们

了解 JavaScript 中的执行上下文

terry 2年前 (2023-09-07) 阅读数 170 #Vue

什么是执行上下文?

执行上下文是分析和执行实际 JavaScript 代码的环境的抽象概念。

执行上下文的重要性在于,它提供了一个抽象模型,可以让我们更容易理解js的运行机制。同时,执行上下文对于理解js内存、闭包、垃圾回收等都有着深刻的意义。它允许我们在不太了解底层代码的情况下分析内存和执行过程。

执行上下文可以分为三类:

  • 全局执行上下文:只有一个,由客户端浏览器创建,通常是一个窗口;
  • 函数执行上下文:可以有无数个,只有在函数调用时才会创建,每次调用函数时都会创建一个新的执行上下文;
  • eval执行上下文:指eval中的代码,一般不推荐使用。

许多执行上下文可以使用执行堆栈进行管理。

执行堆栈

执行堆栈,也称为调用堆栈,是一种后进先出的结构,用于存储代码在执行过程中所需的上下文。

代码第一次执行时,全局执行上下文被放置在栈底,然后根据函数调用将函数执行上下文移动到栈顶。当栈顶的函数终止时,其对应的函数执行上下文将从执行栈中弹出,上下文控制权将转移到当前执行栈的下一个执行上下文。

var a = 'Hello World!';

function first() {  
  console.log('Inside first function');  
  second();  
  console.log('Again inside first function');  
}

function second() {  
  console.log('Inside second function');  
}

first();  
console.log('Inside Global Execution Context');

// Inside first function
// Inside second function
// Again inside first function
// Inside Global Execution Context
 

image.pngimage.png

创建执行上下文

执行上下文的创建分为三个阶段:

  • 确保它指向
  • 创建词汇环境
  • 创建可变环境

确保它指向

  • 在全局上下文中,它指向全局对象。在浏览器中,它指向一个窗口对象。在nodejs中它指向该文件所在的模块;
  • 在函数的上下文中,这取决于函数的调用方式。

创建词汇环境

词汇环境由两部分组成:

  • 环境记录:保存定义的变量和函数;
  • 链接到外部环境:可访问的外部词汇环境

词汇环境可分为:

  • 全局环境:这是一个没有外部环境的词法环境,因此对外部环境的引用为空。它有一个全局对象(窗口)和关联的属性和方法,以及用户定义的全局变量;
  • 功能环境:外部环境的参考可以是全局环境,也可以是功能环境。函数中的用户定义变量存储在环境记录中。

可以看下面的伪代码,更直观:

GobelExectionContext = {           // 全局执行上下文
    LexicalEnvironment: {          // 词法环境
        EnvironmentRecord: {       // 环境记录
            Type: "Object",        // 对象环境记录
            ......
        },  
        outer: <null>                // 对外部环境的引用
    }
}
FunctionExectionContext = {       // 函数执行上下文
    LexicalEnvironment: {         // 词法环境
        EnvironmentRecord: {      // 环境记录
            Type: "Declarative",  // 声明性环境记录
            ......
        }, 
        outer: <GobelEvironment or FunctionEvironment>  // 对外部环境的引用
    }
}
 

创造一个可变的环境

环境变量也是一个词法环境,因此它具有前面提到的词法环境的属性。

在es6中,变量环境和词法环境的区别在于前者用于存储用var定义的变量,后者用于存储声明的函数和变量(let、const)。

您可以看到以下示例:

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

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

c = multiply(20, 30);
 

执行上下文如下:

GobelExectionContext = {           // 全局执行上下文
    LexicalEnvironment: {          // 词法环境
        EnvironmentRecord: {       // 环境记录
            Type: "Object",        // 对象环境记录
            a: < uninitialized >,
            b: < uninitialized >,
            multiply: < func >
        },  
        outer: <null>               // 对外部环境的引用
    }
    
    VariableEnvironment: {          // 变量环境
        EnvironmentRecord: {        
            Type: "Object",         // 对象环境记录
            c: undefined,  
        }  
        outer: <null>      
    }  
}
FunctionExectionContext = {       // 函数执行上下文
    LexicalEnvironment: {         // 词法环境
        EnvironmentRecord: {      // 环境记录
            Type: "Declarative",  // 声明性环境记录
            Arguments: {0: 20, 1: 30, length: 2},
        },
        outer: <GobelLexicalEvironment> 
    }
    
    VariableEnvironment: {  
        EnvironmentRecord: {  
            Type: "Declarative",   // 声明性环境记录
            g: undefined,  
        }  
        outer: <GobelLexicalEvironment> 
    }
}
 

这里可以看到支持变量的原因:变量在环境变量中以未定义的方式存储(用var声明);变量以未初始化的形式存储在词法环境中(使用 let 和 const 声明),因此在使用 let 和 const 声明之前使用变量将导致错误。

执行上下文的执行

到了这个阶段,对变量的赋值就完成了,即上面的执行上下文变成了:

GobelExectionContext = {           // 全局执行上下文
    LexicalEnvironment: {          // 词法环境
        EnvironmentRecord: {       // 环境记录
            Type: "Object",        // 对象环境记录
            a: 20,
            b: 30,
            multiply: < func >
        },  
        outer: <null>               // 对外部环境的引用
    }
    
    VariableEnvironment: {          // 变量环境
        EnvironmentRecord: {        
            Type: "Object",         // 对象环境记录
            c: <multiply>,  
        }  
        outer: <null>      
    }  
}
FunctionExectionContext = {       // 函数执行上下文
    LexicalEnvironment: {         // 词法环境
        EnvironmentRecord: {      // 环境记录
            Type: "Declarative",  // 声明性环境记录
            Arguments: {0: 20, 1: 30, length: 2},
        },
        outer: <GobelLexicalEvironment> 
    }
    
    VariableEnvironment: {  
        EnvironmentRecord: {  
            Type: "Declarative",  // 声明性环境记录
            g: 20,  
        }  
        outer: <GobelLexicalEvironment> 
    }
}
 

以上内容为作者个人理解。如果有任何错误,请报告!

参考:

了解JS执行上下文的文章

了解 JavaScript 中的执行上下文和执行堆栈

js没那么简单(一)——执行上下文

已预编译

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门