JavaScript 的编译与执行原理

文章目录

  • 前言
    • 🧠 一、JavaScript 编译与执行过程
      • 1. 编译阶段(发生在代码执行前)
        • ✅ 1.1 词法分析(Lexical Analysis)
        • ✅ 1.2 语法分析(Parsing)
        • ✅ 1.3 语义分析与生成执行上下文
    • 🧰 二、执行阶段
      • ✅ 2.1 创建执行上下文(Execution Context)
      • ✅ 2.2 变量环境 vs 词法环境
    • 🔁 三、作用域、作用域链与闭包
      • ✅ 3.1 作用域(Scope)
      • ✅ 3.2 作用域链(Scope Chain)
      • ✅ 3.3 闭包(Closure)
    • 🔄 四、循环作用域与经典陷阱
      • ✅ 4.1 for 循环中 var 的作用域陷阱
    • 🔍 五、执行上下文栈(ECS)
    • 🔐 六、总结:如何理解闭包与作用域链的结合
    • 📌 图示记忆(简化示意)
    • 总结


前言

系统深入地讲解 JavaScript 的编译与执行原理,并结合作用域、闭包、作用域链等核心概念,构建一个完整的知识体系。


🧠 一、JavaScript 编译与执行过程

虽然 JavaScript 是解释型语言,但它在执行前仍然会经历编译阶段(由现代 JavaScript 引擎完成,如 V8)。整体过程如下:

1. 编译阶段(发生在代码执行前)

包括以下几步:

✅ 1.1 词法分析(Lexical Analysis)
  • 将源代码拆解成词法单元(Token)
  • 例如:let a = 10;leta=10;
  • 负责这一阶段的是词法分析器(Lexer)。
// 代码
let x = 10 + y;// 生成的tokens
[{ type: 'Keyword', value: 'let' },{ type: 'Identifier', value: 'x' },{ type: 'Punctuator', value: '=' },{ type: 'Numeric', value: '10' },{ type: 'Punctuator', value: '+' },{ type: 'Identifier', value: 'y' },{ type: 'Punctuator', value: ';' }
]

关联知识:
词法环境是 JavaScript 引擎内部用来管理变量和函数作用域的机制,它是理解作用域和闭包的核心概念。

词法环境的组成
一个词法环境包含两部分:

​​环境记录(Environment Record)​​:存储变量和函数声明的实际位置
​​对外部词法环境的引用(Outer Lexical Environment)​​:形成作用域链

// 示例代码
let x = 10;function foo() {let y = 20;console.log(x + y);
}// 对应的词法环境结构
globalLexicalEnvironment = {environmentRecord: { x: 10, foo: <function> },outer: null
}fooLexicalEnvironment = {environmentRecord: { y: 20 },outer: globalLexicalEnvironment
}

词法环境的特性
​​静态性​​:在代码编写阶段就已确定(词法作用域)
​​嵌套性​​:可以形成多层嵌套结构
​​持久性​​:被闭包引用的词法环境不会被销毁

✅ 1.2 语法分析(Parsing)
  • 将 Token 转换为 抽象语法树(AST)
  • AST 是代码结构的树状表示,每个节点代表代码结构的一个成分。
  • 语法分析器(Parser)处理这一步。
let x = 10 + y;
// 生成的AST结构
{type: "VariableDeclaration",kind: "let",declarations: [{type: "VariableDeclarator",id: { type: "Identifier", name: "x" },init: {type: "BinaryExpression",operator: "+",left: { type: "Literal", value: 10 },right: { type: "Identifier", name: "y" }}}]
}
✅ 1.3 语义分析与生成执行上下文
  • 变量提升作用域环境创建函数声明处理

  • 此时创建:

    • 执行上下文栈(Execution Context Stack)
    • 词法环境(Lexical Environment)
    • 变量环境(Variable Environment)

🧰 二、执行阶段

编译完成后,进入代码执行:

✅ 2.1 创建执行上下文(Execution Context)

每个函数/全局代码执行时,会创建一个上下文环境:

  • 包含:

    • 变量环境(变量/函数声明)
    • 词法环境(作用域)
    • this 绑定
    • 外部环境引用(outer)

✅ 2.2 变量环境 vs 词法环境

  • 变量环境

    • 存储变量、函数声明(var/函数声明)
  • 词法环境(Lexical Environment):

    • 变量环境 + 外部环境引用(outer)
    • 用于作用域链的构建。

🔁 三、作用域、作用域链与闭包

✅ 3.1 作用域(Scope)

  • 定义变量和函数的可访问范围

  • 分为:

    • 全局作用域
    • 函数作用域
    • 块级作用域(let/const)

✅ 3.2 作用域链(Scope Chain)

  • 当前执行上下文的词法环境中包含对上级词法环境的引用
  • 在查找变量时,从当前作用域出发,逐层向上查找,直到全局作用域。
function outer() {let a = 10;function inner() {console.log(a); // 通过作用域链访问 outer 的 a}inner();
}
outer();

✅ 3.3 闭包(Closure)

  • 闭包是函数+定义它的词法环境的组合
  • 当一个函数“脱离”了它定义时的作用域,仍然“记住”当时的变量。
function makeCounter() {let count = 0;return function () {return ++count;}
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
  • count 保存在 makeCounter 的词法环境中,被返回的函数形成闭包访问它。

🔄 四、循环作用域与经典陷阱

✅ 4.1 for 循环中 var 的作用域陷阱

for (var i = 0; i < 3; i++) {setTimeout(() => {console.log(i); // 输出三个 3}, 0);
}
  • 原因:var 没有块级作用域,i 绑定在同一个词法环境中。
  • 修复方法:使用 let(创建新的词法环境)
for (let i = 0; i < 3; i++) {setTimeout(() => {console.log(i); // 输出 0 1 2}, 0);
}

🔍 五、执行上下文栈(ECS)

每当函数调用时,会创建新的执行上下文并压栈

  1. 创建全局执行上下文 → 入栈
  2. 调用函数 → 创建函数执行上下文 → 入栈
  3. 函数执行完毕 → 执行上下文出栈

🔐 六、总结:如何理解闭包与作用域链的结合

  1. JavaScript 中函数定义时就“捕获”了其父级词法环境(静态作用域)。
  2. 执行时,通过作用域链查找变量,先本地再向上查找。
  3. 如果内部函数延迟执行(异步或返回),那么闭包可以“保持”对外部变量的访问。

📌 图示记忆(简化示意)

makeCounter() 创建执行上下文
└── 词法环境 {count = 0,outer = Global}返回的匿名函数 闭包:
└── 词法环境 {outer = makeCounter.LE}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

总结

  • ​​词法环境​​是 JavaScript 作用域管理的核心机制,具有静态性和嵌套性
  • 循环中使用 let 会为每次迭代创建新的词法环境副本
  • ​​词法分析​​和​​语法分析​​是编译的前期阶段,与运行时词法环境不同
  • JavaScript 引擎通过这种机制实现块级作用域和闭包功能
  • 理解这些概念有助于编写正确的作用域代码和调试复杂的作用域问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/81350.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WORD个人简历单页326款模版分享下载

WORD个人简历模版下载&#xff1a;WORD个人简历模版https://pan.quark.cn/s/7e79a822c490

Android 中 显示 PDF 文件内容(AndroidPdfViewer 库)

PDFView 是一个用于在 Android 应用中显示 PDF 文档的库。它提供了丰富的功能和灵活的配置选项&#xff0c;使得开发者能够轻松地在应用中嵌入 PDF 阅读器。 一、 添加依赖 在模块的 build.gradle 文件中添加以下依赖&#xff1a; // pdfimplementation("com.github.bar…

微信小程序学习之搜索框

1、第一步&#xff0c;我们在index.json中引入vant中的搜索框控件&#xff1a; {"usingComponents": {"van-search": "vant/weapp/search/index"} } 2、第二步&#xff0c;直接在index.wxml中添加布局&#xff1a; <view class"index…

OpenCL C++ 常见属性与函数

核心对象与属性 对象/属性描述示例cl::Platform表示OpenCL平台cl::Platform::get(&platforms)cl::Device表示计算设备cl::Device::getDefault()cl::Context管理设备、内存和命令队列的上下文cl::Context(contextDevices)cl::CommandQueue命令队列,用于提交命令cl::Command…

Milvus 视角看重排序模型(Rerankers)

在信息检索和生成式人工智能领域&#xff0c;重排序器是优化初始搜索结果顺序的重要工具。重排序器与传统的嵌入模型不同&#xff0c;它将查询和文档作为输入&#xff0c;并直接返回相似度得分&#xff0c;而不是嵌入。该得分表示输入查询和文档之间的相关性。 重排序器通常在…

C语言:gcc 如何调用 Win32 打开文件对话框 ?

在 Windows 平台上使用 gcc 调用原生 Win32 API 实现文件打开对话框是可行的&#xff0c;但需要直接使用 Win32 的 GetOpenFileName 函数&#xff08;位于 commdlg.h 头文件&#xff0c;依赖 comdlg32.lib 库&#xff09;。以下是完整实现步骤和代码示例&#xff1a; 编写 file…

计算机视觉与深度学习 | Python实现EMD-SSA-VMD-LSTM时间序列预测(完整源码和数据)

EMD-SSA-VMD-LSTM混合模型 一、环境配置与依赖二、数据生成&#xff08;示例数据&#xff09;三、多级信号分解1. 经验模态分解&#xff08;EMD&#xff09;2. 奇异谱分析&#xff08;SSA&#xff09;3. 变分模态分解&#xff08;VMD&#xff09; 四、数据预处理1. 归一化处理2…

vue配置子路由,实现点击左侧菜单,内容区域显示不同的内容

文章目录 一、路由链路二、实现步骤准备二级路由下的.vue文件配置子路由声明router-view标签为菜单项 el-menu-item 设置index属性&#xff0c;设置点击后的路由路径 三、参考资料 一、路由链路 二、实现步骤 准备二级路由下的.vue文件 配置子路由 router/index.js import {…

ModuleNotFoundError: No module named ‘SDToolbox‘

(py311) C:>python Python 3.11.11 | packaged by Anaconda, Inc. | (main, Dec 11 2024, 16:34:19) [MSC v.1929 64 bit (AMD64)] on win32 Type “help”, “copyright”, “credits” or “license” for more information. from SDToolbox import PostShock_eq Tracebac…

Hi3516DV500刷写固件

hi3516DV500刷固件 1、硬件连接 2、软件准备 3、刷固件步骤 一、硬件连接 特别注意的是&#xff0c;串口的接线顺序 通过网线连接好笔记本和开发板后&#xff0c;需要确认一下网口水晶头是否闪烁&#xff0c;以确认网络物理是否连通 二、软件资源准备 固件包准备 打开工具…

正则表达式r前缀使用指南

正则表达式中的 r&#xff1a;解锁字符串转义的魔法 正则表达式是处理字符串的强大工具&#xff0c;但它常常伴随着转义字符的复杂性。如果你曾因 \n、\t 或 \\ 的使用而困惑&#xff0c;那么这篇文章将为你揭开谜底&#xff0c;解释为什么 r 是正则表达式中的「神奇武器」。本…

网络攻防模拟:城市安全 “数字预演”

在当今数字化快速发展的时代&#xff0c;网络安全和城市安全面临着前所未有的挑战。为有效应对这些挑战&#xff0c;利用先进的技术搭建模拟演练平台至关重要。图扑软件的 HT for Web 技术&#xff0c;为网络攻防模拟与城市安全演练提供了全面且高效的解决方案。 三维场景搭建&…

AI模型开发全流程笔记

一、训练数据准备阶段 数据采集标准 格式要求&#xff1a;严格QA对形式&#xff08;1问1答&#xff09; 数量基准&#xff1a; 基础量&#xff1a;500组QA对 优化量&#xff1a;800-1000组QA对 内容规范&#xff1a; 聚焦单一业务节点&#xff08;如售后场景&#xff09; …

1688 数据接口调用秘籍:高效获取商品实时信息的开发指南

在电商行业竞争白热化的当下&#xff0c;企业想要抢占市场先机&#xff0c;实时掌握商品信息至关重要。作为国内 B2B 电商巨头&#xff0c;1688 平台汇聚海量商品资源&#xff0c;通过高效调用其数据接口获取商品实时信息&#xff0c;能为企业价格策略制定、库存管理、竞品分析…

milvus学习笔记

本文主要由AI生成&#xff0c;请注意自己查看源代码校验。 Milvus v2.4 系统架构概览 Milvus 采用分布式微服务架构&#xff0c;将计算层&#xff08;Proxy、QueryCoord、QueryNode、IndexCoord、DataCoord、DataNode 等&#xff09;与存储层&#xff08;Pulsar、MinIO/S3、e…

使用教程:8x16模拟开关阵列可级联XY脚双向导通自动化接线

以下通过点亮LED进行基本使用流程演示&#xff0c;实际可以连接复杂外设&#xff08;SPI、CAN、ADC等&#xff09; 单模块使用 RX、TX、5V和GND接到串口模块&#xff1b;X5接5V&#xff1b;Y2接LED;LED-接GND 串口模块插上电脑后&#xff0c;LED没有亮&#xff1b;因为此时模…

HarmonyOS NEXT~鸿蒙应用上架指南:HarmonyOS应用发布全流程解析

HarmonyOS NEXT&#xff5e;鸿蒙应用上架指南&#xff1a;HarmonyOS应用发布全流程解析 引言 随着华为鸿蒙操作系统(HarmonyOS)生态的快速发展&#xff0c;越来越多的开发者希望将自己的应用上架到鸿蒙应用市场。本文将详细介绍鸿蒙应用上架的全流程&#xff0c;帮助开发者顺…

20250517 我设想一个空间,无限大,空间不与其中物质进行任何作用,甚至这个空间能容纳可以伸缩的空间

1.我设想一个空间&#xff0c;无限大&#xff0c;空间不与其中物质进行任何作用&#xff0c;甚至这个空间能容纳可以伸缩的空间 您设想的这个空间具有一些有趣的特点&#xff1a; 无限大&#xff1a;空间本身没有边界或限制&#xff0c;理论上可以容纳无限多的物质或结构。非…

使用 Kaniko来构建镜像

使用 Kaniko来构建镜像 Kaniko 是一种专注于容器镜像构建的开源工具&#xff0c;其核心设计理念与 Docker 存在显著差异。以下从功能定位、技术实现和适用场景三方面进行对比分析&#xff1a; 一、Kaniko 的核心特性 无需 Docker 守护进程 Kaniko 直接在容器或 Kubernetes 集…

webman用nginx代理静态json文件的异步跨域

场景 有.json文件置于webman的public目录下&#xff0c;使用了nginx做代理&#xff0c;直接访问文件是可以正常加载的&#xff0c;但跨域浏览器就无法加载文件。 nginx配置 文件是否存在于跟目录&#xff0c;存在则设置请求头&#xff0c;不存在则将请求交给webman处理即可。…