必知必会的JavaScript执行上下文

JavaScript中的执行上下文是一个抽象的概念,它是JavaScript引擎用于管理执行代码的内部数据结构。每当JavaScript引擎执行一段代码时,都会创建一个执行上下文,该上下文将包含代码执行所需的所有信息,包括变量、函数、对象等。

一、执行上下文的数据结构

JavaScript中的执行上下文由三个不同的对象构成,它们分别是变量对象作用域链this指向
必知必会的JavaScript执行上下文

1. 变量对象

变量对象是执行上下文的一个组成部分,它是一个与当前执行环境相关的特殊对象,用于存储在执行上下文中声明的所有变量和函数声明。变量对象可以看作是一个容器,用于存储当前执行上下文中的变量和函数声明。

在 JavaScript 中,变量对象被创建并初始化为一个空对象,在函数执行过程中,它会被填充相应的变量和函数声明。变量对象在全局执行上下文或函数执行上下文中都存在,但它们的作用稍有不同。在全局执行上下文中,变量对象被称为全局对象,它是 window 对象的引用。而在函数执行上下文中,变量对象被称为活动对象,它存储了当前函数执行过程中的所有变量和函数声明。

2. 作用域链

作用域链是由当前执行上下文和所有外部环境的变量对象构成的。作用域链的作用是保证执行环境中对变量和函数的访问权限。

当一个函数被调用时,它会创建一个新的执行上下文,并将其添加到作用域链的顶部。这个新的执行上下文包含着自己的变量对象,以及指向外部环境的指针。这样,就可以通过作用域链来访问外部环境中的变量和函数。作用域链的深度取决于函数的嵌套层数和代码中的作用域嵌套情况。在代码中合理地使用作用域链,可以有效地避免变量名冲突和数据泄露等问题。

必知必会的JavaScript执行上下文

3. this指向

this指向被调用时所在的上下文对象。在JavaScript语言中,this是一个关键字,用于引用上下文对象。换句话说,this是一个指向当前函数所属的对象的指针,可以在函数内部使用。如果函数被直接调用,则上下文对象为全局对象,如果函数作为某个对象的方法调用,则上下文对象为该对象。

必知必会的JavaScript执行上下文

二、执行上下文堆栈

执行上下文堆栈是指当 JavaScript 引擎在执行代码过程中,每当遇到一个函数调用时,就会创建一个新的执行上下文,并将其压入一个执行上下文栈中。这个栈被称为执行上下文堆栈(Execution Context Stack),也被称为调用栈(Call Stack)。当函数执行完成后,它的执行上下文会从堆栈中弹出,控制流程回到调用该函数的上一个执行上下文。这个过程一直重复,直到执行上下文堆栈为空。

执行上下文堆栈的作用是管理执行上下文的创建和销毁,以及控制代码的执行顺序。每当 JavaScript 引擎遇到函数调用时,它会将当前执行上下文压入执行上下文堆栈,并创建一个新的执行上下文,然后将其压入堆栈。当函数执行完成后,引擎会将当前执行上下文从堆栈中弹出,并将控制流程返回到调用该函数的执行上下文。这个过程一直重复,直到执行上下文堆栈为空。

执行上下文堆栈的大小是有限的,当堆栈大小超过限制时,会导致栈溢出错误。因此,在编写 JavaScript 代码时,应该避免出现过多的嵌套函数调用,以及避免使用递归函数等可能导致堆栈溢出的代码。

执行上下文栈经历过程代码示例:

function out(){
    function inner(){}
    inner();
  }
  out();
  /*
    这个函数的执行上下文栈会经历一下过程
    ECS.push(globalContext);
    ECS.push(outContext);
    ECS.push(innerContext);
    ECS.pop(outContext);
    ECS.pop(innerContext);
    ECS.pop(globalContext);
  */

三、执行上下文的生命周期

执行上下文的生命周期:

  1. 创建阶段:在进入代码执行阶段之前,JavaScript引擎会先创建当前执行上下文的变量对象,即VO(Variable Object)对象。变量对象包括函数参数、函数声明、变量声明等。
  2. 代码执行阶段:在代码执行阶段,JavaScript引擎会按照一定的规则执行代码,并修改变量对象的值。在执行过程中,如果需要调用其他函数,则会创建新的执行上下文,并将其压入执行上下文堆栈中。
  3. 执行完成阶段:当代码执行完成后,JavaScript引擎会将当前执行上下文从堆栈中弹出,控制流程回到调用该函数的上一个执行上下文。

执行上下文的生命周期决定了JavaScript程序的执行顺序和变量的访问范围。理解执行上下文的生命周期,有助于我们更好地理解JavaScript的执行过程。

四、与作用域之间的关系

词法作用域和执行上下文是 JavaScript 中两个不同的概念。

词法作用域是指变量的作用域在代码编译阶段就已经确定,与函数调用的位置无关。在 JavaScript 中,变量的作用域是由函数和代码块(如 if/else 语句、for 循环等)决定的。作用域规定了变量在哪些代码块中可以被访问。

执行上下文是指 JavaScript 引擎在执行代码时,创建的一个内部数据结构,用于存储在执行代码所需的所有信息,包括变量、函数、对象等。每当 JavaScript 引擎执行一段代码时,都会创建一个执行上下文,该上下文将包含代码执行所需的所有信息。

虽然词法作用域和执行上下文是两个不同的概念,但它们之间有紧密的联系。在 JavaScript 中,执行上下文中的作用域链就是由词法作用域决定的。也就是说,执行上下文中的作用域链是由当前执行上下文的变量对象和所有外部环境的变量对象构成的。在函数嵌套的情况下,内部函数可以访问外部函数的变量和函数,但外部函数不能访问内部函数的变量和函数。

五、写在最后

理解JavaScript执行上下文和作用域对于编写高质量的JavaScript代码至关重要。JavaScript的执行上下文机制决定了变量和函数声明的作用域和可见性,而作用域链则决定了代码中变量和函数的访问权限。正确地理解和使用执行上下文和作用域,可以提高JavaScript代码的可读性、可维护性和性能。深入学习JavaScript执行上下文和作用域是每个JavaScript开发者都应该做的事情。

原文链接:https://juejin.cn/post/7218447209120645157 作者:forrest酱

(0)
上一篇 2023年4月5日 下午5:08
下一篇 2023年4月6日 上午10:05

相关推荐

发表回复

登录后才能评论