魅力程序猿

  • 首页
  • Java
  • Android
  • APP
    • 扑克计分器
    • Video Wallpaper
  • 联系我
  • 关于我
  • 资助
道子
向阳而生
  1. 首页
  2. AI技术
  3. 正文

V8引擎 精品漫游指南--Ignition篇(下 一) 动态执行前的事情

2026年5月2日 10点热度 0人点赞 0条评论

📰 来源: 博客园


1. 前文总结 和 运行期前置知识

这个系列文章,已经写了一少半了,现在终于到了动态执行阶段了。

我们首先需要梳理一下知识,这部分内容,相对独立,但是都算是比较重要的知识点。

  • 预编译的说法为什么不建议使用

    在我们平时看文章,看资料,甚至是看一些比较权威的文档时,预编译 这个术语非常常见。但是,在js中,预编译 是个伪术语,是一些教材教程在以前的js教学中,为了解释变量提升等一些问题,生造出来的一个词语,后来,只要是运行期以前的 甚至是在和运行期交织发生的一些动作流程,统统装进了 预编译 这个大口袋里。大部分人,也就不求甚解的接受并使用了这个说法。但是,这是一个不规范且容易引发歧义的词汇。在传统编译语言中,预处理、编译与执行通常有明确的时间边界;在现代 JavaScript 环境,这些阶段高度交织。规范(ECMAScript (ECMA-262))并不使用“预编译”一词,而是通过“执行上下文的创建阶段(creation / declaration instantiation)”来描述声明的注册与初始化。实际引擎(例如 V8)则采用惰性解析与按需编译:先做必要的解析与作用域分析,再由解释器生成字节码(如 Ignition)或在运行时将热点编译为机器码(由优化器完成)。

    对于js,可以分为如下四个宏观的阶段:

    词法分析:把源代码分成记号(tokens)。

    语法分析(Parsing):构建抽象语法树(AST),确定静态作用域结构。

    执行上下文创建阶段(Creation / Declaration Instantiation):为全局或每次函数调用登记标识符(函数声明整体被绑定;var 注册并初始化为 undefined;let/const 注册但处于 TDZ)。这一步决定了变量可见性和提升行为,但不等于把所有代码预先编译成机器码。

    执行阶段:逐条执行语句;遇到函数调用重复执行上一 步。现代引擎会在此阶段对运行行为收集反馈,并按需触发优化编译。

  • 预编译的说法为什么不建议使用

    在我们平时看文章,看资料,甚至是看一些比较权威的文档时,预编译 这个术语非常常见。但是,在js中,预编译 是个伪术语,是一些教材教程在以前的js教学中,为了解释变量提升等一些问题,生造出来的一个词语,后来,只要是运行期以前的 甚至是在和运行期交织发生的一些动作流程,统统装进了 预编译 这个大口袋里。大部分人,也就不求甚解的接受并使用了这个说法。但是,这是一个不规范且容易引发歧义的词汇。在传统编译语言中,预处理、编译与执行通常有明确的时间边界;在现代 JavaScript 环境,这些阶段高度交织。规范(ECMAScript (ECMA-262))并不使用“预编译”一词,而是通过“执行上下文的创建阶段(creation / declaration instantiation)”来描述声明的注册与初始化。实际引擎(例如 V8)则采用惰性解析与按需编译:先做必要的解析与作用域分析,再由解释器生成字节码(如 Ignition)或在运行时将热点编译为机器码(由优化器完成)。

    对于js,可以分为如下四个宏观的阶段:

    词法分析:把源代码分成记号(tokens)。

    语法分析(Parsing):构建抽象语法树(AST),确定静态作用域结构。

    执行上下文创建阶段(Creation / Declaration Instantiation):为全局或每次函数调用登记标识符(函数声明整体被绑定;var 注册并初始化为 undefined;let/const 注册但处于 TDZ)。这一步决定了变量可见性和提升行为,但不等于把所有代码预先编译成机器码。

    执行阶段:逐条执行语句;遇到函数调用重复执行上一 步。现代引擎会在此阶段对运行行为收集反馈,并按需触发优化编译。

  • 全局创建阶段和函数创建阶段的区别

    无论是全局还是函数,在代码真正执行前都会经历“创建阶段”(进行变量和函数声明的提升),但两者有本质区别:

    作用域范围:

    • 全局阶段:影响整个程序,声明的变量和函数最终挂载到全局环境(浏览器中为 window)。

    • 函数阶段:每调用一次函数,生成一个完全独立的执行上下文,仅对函数体内部有效,互不干扰。

    变量遮蔽(shadowing):

    • 在函数内部,如果存在与全局同名的变量,函数内的局部变量会“遮蔽”全局变量。即使全局变量在早期的全局阶段已经存在,函数内部在自己的创建阶段会优先登记局部标识符。
  • 全局创建阶段和函数创建阶段的区别

    无论是全局还是函数,在代码真正执行前都会经历“创建阶段”(进行变量和函数声明的提升),但两者有本质区别:

  • 全局阶段:影响整个程序,声明的变量和函数最终挂载到全局环境(浏览器中为 window)。

  • 全局阶段:影响整个程序,声明的变量和函数最终挂载到全局环境(浏览器中为 window)。

  • 函数阶段:每调用一次函数,生成一个完全独立的执行上下文,仅对函数体内部有效,互不干扰。

  • 函数阶段:每调用一次函数,生成一个完全独立的执行上下文,仅对函数体内部有效,互不干扰。

    变量遮蔽(shadowing):

  • 在函数内部,如果存在与全局同名的变量,函数内的局部变量会“遮蔽”全局变量。即使全局变量在早期的全局阶段已经存在,函数内部在自己的创建阶段会优先登记局部标识符。
  • 四个宏观的阶段

    JavaScript 代码的完整生命周期分为以下四个阶段:

    1. 词法分析(Lexical Analysis)

    • 目的:将源代码字符串分解成一系列记号(Tokens)。
    • 内容:识别关键字、标识符、操作符、数字、字符串、注释等最小语法单元。

    2. 语法分析(Syntax Analysis / Parsing)

    • 目的:将记号序列转换成抽象语法树(AST)。
    • 内容:检查代码结构是否符合语法规则,构建反映代码静态结构的蓝图。

    3. 执行上下文创建阶段(Creation/Instantiation Phase)

    • 全局上下文创建:
      • 创建全局对象(Global Object)。
      • 扫描全局代码:将函数声明整体提升;将 var 变量注册并初始化为 undefined;将 let/const 注册,但置于“暂时性死区(TDZ)”。
      • 建立全局词法环境,其外部引用为 null。
      • 计算 this 绑定。
    • 函数上下文创建(每次调用时触发):
      • 确定外部环境引用(Outer Environment Reference),构建作用域链。
      • 创建局部词法环境,绑定形参与实参,创建 arguments 对象。

      • 🔗 原文链接: 点击阅读原文

  • 标签: AI 人工智能 技术博客
    最后更新:2026年5月2日

    daozi

    这个人很懒,什么都没留下

    点赞
    < 上一篇

    文章评论

    razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复
    搜索
    联系方式

    QQ群:179730949
    QQ群:114559024
    欢迎您加入Android大家庭
    本人QQ:136049925

    赐我一丝安慰
    给我一点鼓励

    COPYRIGHT © 2023 魅力程序猿. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    豫ICP备15000477号