你真的了解执行上下文吗?

深入理解 JavaScript 执行上下文 阅读详情

执行上下文

执行上下文 可以理解为当前代码的执行环境,同一个函数在不同的环境中执行,会因为访问数据的不同产生不一样的结果。

执行上下文分为三种:

  • 全局执行上下文:只有一个,程序首次运行时创建,它会在浏览器中创建一个全局对象(window对象),使this指向这个全局对象
  • 函数执行上下文:函数被调用时创建,每次调用都会为该函数创建一个新的执行上下文
  • Eval 函数执行上下文:运行eval函数中的代码时创建的执行上下文,少用且不建议使用

执行上下文栈

执行上下文栈(Execution context stack,ECS),也叫函数调用栈(call stack),是一种拥有 LIFO(后进先出)数据结构的栈,用于存储代码执行时创建的执行上下文

由于JS是单线程的,每次只能做一件事情,通过这种机制,我们能够追踪到哪个函数正在执行,其他函数在调用栈中排队等待执行。

JS引擎第一次执行脚本时,会创建一个全局执行上下文压到栈顶,然后随着每次函数的调用都会创建一个新的执行上下文放入到栈顶中,随着函数执行完毕后被执行上下文栈顶弹出,直到回到全局的执行上下文中。

代码实例🌰

var color = 'blue';

function changeColor() {
  var anotherColor = 'red';
  
  function swapColors() {
    var tempColor = anotherColor;
    anotherColor = color;
    color = tempColor;
  }
  
  swapColors();
}

changeColor();

console.log(color); // red
复制代码

执行过程可以在 devTool 的 call stack 中看到,其中 anonyomus 为全局上下文栈;其余为函数上下文栈

图解:

执行过程:

  1. 首先创建了全局执行上下文,压入执行栈,其中的可执行代码开始执行。
  2. 然后调用 changeColor 函数,JS引擎停止执行全局执行上下文,激活函数 changeColor 创建它自己的执行上下文,且把该函数上下文放入执行上下文栈顶,其中的可执行代码开始执行。
  3. changeColor 调用了 swapColors 函数,此时暂停了 changeColor 的执行上下文,创建了 swapColors 函数的新执行上下文,且把该函数执行上下文放入执行上下文栈顶。
  4. 当 swapColors 函数执行完后,其执行上下文从栈顶出栈,回到了 changeColor 执行上下文中继续执行。
  5. changeColor 没有可执行代码,也没有再遇到其他执行上下文了,将其执行上下文从栈顶出栈,回到了 全局执行上下文 中继续执行。
  6. 一旦所有代码执行完毕,JS引擎将从当前栈中移除 全局执行上下文。
注意:函数中,遇到return能直接终止可执行代码的执行,因此会直接将当前上下文弹出栈。
复制代码

使用 ECStack 来模拟调用栈:

ECStack=[]
复制代码

JS第一次执行代码时就会遇到全局代码,执行上下文栈会压入一个全局上下文,我们用 globalContext 表示它,只有当整个应用程序结束的时候,ECStack 才会被清空,所以 ECStack 最底部永远有个 globalContext:

ECStack.push(globalContext)
复制代码

使用伪代码模拟上述代码行为:

ECStack.push(<changeColor> functionContext);
ECStack.push(<swapColors> functionContext);

// swapColors出栈
ECStack.pop();
// changeColor出栈
ECStack.pop();
复制代码

为了巩固一下执行上下文的理解,我们再来绘制一个例子的演变过程,这是一个简单的闭包例子。

function f1() {
  var n = 999;
  function f2() {
    console.log(n);
  }
  return f2;
}
f1()() // 999
复制代码

使用伪代码模拟上述代码行为:

ECStack.push(<f1> functionContext);
// f1出栈
ECStack.pop();

ECStack.push(<f2> functionContext);
// f2出栈
ECStack.pop();
复制代码

因为f1中的函数f2在f1的可执行代码中,并没有被调用执行,因此执行f1时,f2不会创建新的上下文,而直到f2执行时,才创建了一个新的。具体演变过程如下。

es3版本

es3版本执行上下文内有三个重要属性:

  • 变量对象 VO(variable object)
  • 作用域链(scope chain)
  • this

可以将每个执行上下文抽象为一个对象。

执行上下文的组成代码示例:

executionContextObj = {
  scopeChain: { /* 变量对象(variableObject)+ 所有父执行上下文的变量对象*/ },
  [variableObject | activationObject]: {
    /*函数 arguments/参数,内部变量和函数声明 */
    arguments,
    ...
  },
  this: {}
}
复制代码

变量对象

变量对象 是与执行上下文相联的数据作用域,用来存储上下文中定义的变量和函数声明。

不同执行上下文中的变量对象也不一样:

  • 全局上下文 中的变量对象就是全局对象,在浏览器中就是 window 对象。在顶层 JavaScript 代码中,可以用关键字 this 引用全局对象。所有的全局变量和函数都是作为 window 的属性和方法存在。
    console.log(this) //window
    var a=1 //挂到window上的属性
    console.log(window.a) //1
    console.log(this.a) //1
复制代码
  • 函数执行上下文 中我们用活动对象 AO (activation object) 来表示变量对象,因为变量对象是规范上的或者说是引擎实现上的,在 JavaScript 环境中是不能被直接访问的,只有当函数被调用时,变量对象被激活为活动对象时,我们才能访问到其中的属性和方法。
  活动对象就是变量对象,只不过处于不同的状态和阶段而已。
复制代码

作用域链

对于 JavaScript 来说作用域及作用域链的变量查询是通过存储在浏览器内存中的执行上下文实现的。当查找变量时,首先从当前上下文中的变量对象查找,如果没有就会往上查找父级作用域中的变量对象,最终找到全局上下文的变量对象,如果没有就报错。这样由多个执行上下文的变量对象构成的链表就叫做作用域链。

关于作用域和作用域链可以参考我的另一篇文章: 掌握JavaScript面试:什么是闭包?

那么有同学就有疑问了,作用域和执行上下文有什么 区别 呢 🎉:

函数执行上下文是在调用函数时, 函数体代码执行之前创建,函数调用结束时就会自动释放。因为不同的调用可能有不同的参数:

var a = 10;
function fn(x) {
  var a = 20;
  console.log(arguments)
  console.log(x)
}
fn(20)
fn(10) // 不同
【白话系列】倍增算法 【序言】         我认为吧,所有能够优化复杂度的算法都是神奇的,所有能够化繁琐为形象的文字都是伟大的。一直觉得倍增算法是个很神奇的东西,所以决定写点东西纪念一下它。但是作为一个非常不称职的OIER,我非常讨厌在看别人的算法解析时整版的i,j,k等我看到鼠标就惯性移到右上角的符号语言,所以我想用最形象的方式来纪念它。 【一】         从前,有一只可爱得不得了的小白兔,它想从 阅读详情

相关推荐

空地多无人平台协同路径规划复现:从建模到Matlab仿真全解析

路径规划是机器人领域的核心基础技术,从单机避障到多平台协同,问题复杂度显著提升。空地协同规划融合无人机与无人车的异构优势,通过将地图分层建模为空中与地面栅格,并采用A*算法生成初始路径、B样条平滑以及改进遗传算法进行任务分配与时间同步优化,能够有效处理几何约束、运动学约束和避碰约束等。该技术广泛应用于区域巡逻、目标搜索、物资转运等任务场景,也是高校论文复现和工程仿真的常见课题。本文从问题建模、算法设计到Matlab代码结构,系统梳理了一套空地多无人平台协同路径规划的复现思路,同时给出坐标系校准、遗传算法收敛

weixin_32175665的博客 250

读《认知科学导论》(萨伽德) 总结

1. 作者的写作思路 本书是建立在对心智的理解采用表征与计算的方式。对心智表征-计算的理解方式是与计算机的本质相联系。计算机本质上是一个符号系统,符号系统包含两个部分,一个是符号,另一个是建立在符号上的操作。对心智采用表征-计算的方式理解,很容易与计算机建立起类比关系。同时人们在探索人工智能领域采用表征-计算方式已经取得了无数辉煌的成就,故表征-计算式现在研究的主流方法。 本书的有两个部分组成

xiaoqiangXX的专栏 3450

【腹腔镜数据集】Cholec80+CholecSeg8k2020+Endoscapes2024

计算机辅助手术的发展旨在提高手术的正确性和安全性。然而,研究人员和工程师却面临着开发和训练更好算法所需的注释数据有限的问题。因此,同步定位与建图(SLAM)等基础算法的发展受到限制。基于Cholec80数据集,从Cholec80中的17个视频片段中提取了8,080个腹腔镜胆囊切除术图像帧,对图像进行注释并向公众发布。该数据集名为 CholecSeg8K。这些图像中的每一个都以十三个类别的像素级注释,这些类别通常在腹腔镜胆囊切除术中发现。

Toky_min的博客 2020

赛灵思Xilinx 7系列FPGA硬件设计知识总结

本文讲述了赛灵思7系列FPGA硬件设计的关键点,为使用该系列FPGA提供硬件设计参考。

csdn_dsw的博客 3621

Qt垂直滚动条QVerticalScrollBar详解:从基础到实战的控件开发指南

本文系统解析Qt中QVerticalScrollBar的用法,从基础概念到进阶技巧。主要内容包括:1)基础认知:介绍其继承关系、作用及典型应用场景;2)核心用法:创建方法、关键属性配置和信号槽连接;3)进阶技巧:自定义样式表美化外观,以及与自定义内容区域的联动实现;4)实战注意事项,如避免循环触发和高DPI适配等。文章强调掌握QVerticalScrollBar对提升Qt滚动类功能开发效率的重要性,并建议通过自定义文本编辑器实践巩固知识点。

专注现代C++实战,从核心语法到高性能编程,助力开发者深入掌握系统级编程精髓。 759

【ComfyUI】SDXL + 单LoRA 房屋平面图渲染装修

本文介绍了一种基于ComfyUI的室内平面设计图自动生成效果图的工作流。该流程通过导入房屋平面图,结合SDXL室内设计模型与北欧风格LoRA模块,快速生成多房间效果展示。工作流包含图像输入、文本处理、模型加载和图像生成等环节,支持风格化渲染和细节补充,适用于建筑设计、家装展示、房地产营销等场景。核心采用SDXL通用室内设计模型和北欧极简LoRA,通过节点衔接实现自动化批量生成,能在短时间内将平面方案转化为逼真的三维效果图。该技术可提升设计呈现效率,辅助客户决策,并应用于教学研究领域。

Mr数据杨 3659

电子元件及其规格书的查找与理解

本内容收录:在电子开发或维修过程中,查找电子元件及其规格书心得体会,以及元件规格书的理解,系个人多年实战经验的系统梳理。内容着重介绍贴片元件代码反查型号的实用技巧,并以三款典型疑难元件为例,详述其完整查找过程与最终型号确认。

让你爱上电路设计 3991

android 如何分析应用的内存(十六)——使用AS查看Android堆

在前面,先介绍了如何使用jdb和VS code查看应用栈相关内容。本文将介绍,如何查看堆中的内容。

安仔的博客 4254

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

上一篇: Mysql神乎乎的MVCC到底该怎么理解
下一篇: Redis 分布式锁遇到的序列化问题
Java斗帝之路
博客等级 码龄7年 2392粉丝 687原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值