🕸️
Web 技术
Web 技术计算机基础数据结构与算法代码设计数据分析Others
  • 💡Web API 一览表
  • HTML
    • 💡HTML 元素一览表
      • 🗒️语义化
      • 🗒️替换元素
      • 🗒️<iframe>
    • ❕HTML 元数据
    • 💡HTML 属性一览表
      • 🗒️src 和 href
      • 🗒️defer 和 sync
    • 🗒️Q&A
      • 语言基础
      • TODO
  • CSS
    • 💡CSS 选择器
    • ❕CSS At-rule
      • 🗒️@container
      • 🗒️@layer
    • 💡CSS 属性一览表
      • 📁布局
        • ❕Flex
        • ❕Grid
      • 📁文本
        • 🗒️font-family
      • 📁UI
        • 🗒️border-image
        • 🗒️box-shadow
      • 📁动画
        • 🗒️运动路径
        • ❕贝塞尔曲线
    • ❕数据类型和函数
    • 💡W3C CSS WG
    • 🗒️Q&A
      • 4.1 语言基础
      • 4.2 编程题
      • TODO
  • JavaScript
    • 💡知识结构
    • 📁数据类型
      • 💡通用知识
      • ❕原始值
      • ❕原始类型
        • 1. Undefined
        • 2. Null
        • 3. Boolean
        • 4. String
        • 5. Number
        • 6. BigInt
        • 7. Symbol
      • ❕Object
        • 🗒️面向对象
        • 🗒️函数对象和构造器对象
        • ❗属性描述符
        • ❗浅拷贝和深拷贝
        • 🗒️iterable object
        • ❗Function
          • 1.4.1 定义函数
          • 1.4.2 函数参数
          • 1.4.3 函数的 this 关键字
          • 1.4.4 箭头函数
          • 1.4.5 bind
          • 1.4.6 call, apply
          • 1.4.7 闭包
          • 1.4.x 顶级内置函数
          • 1.4.x 函数
        • 🗒️内置对象
          • Array 操作篇
          • Set 和 WeakSet
          • Map 和 WeakMap
          • 迭代器和生成器
        • ❗Class
      • ❕字面量
        • 1.7.1 模板字符串
      • ❕类型转换
      • 🗒️原理浅析
        • 1.8.1 String 里的方法
        • 1.8.2 Array 里的方法
      • 🗒️补充内容
        • 1.9.1 值类型和引用类型
        • 1.9.2 数据类型相关
      • 🗒️规范类型
    • 📁运行时
      • ❕Promise
        • ❗实现一个 Promise(1)
        • ❗实现一个 Promise(2)
        • 📝实现一个 Promise(3)
        • 📝最佳实践
      • ❕Event Loop
        • ❕浏览器中的 Event Loop
        • ✍️Node.js 中的 Event Loop
        • 📝使用 Event Loop
      • 🗒️宏观任务和微观任务
      • 🗒️函数的执行过程
      • 🗒️语句的执行过程
      • Proxy
      • Reflect
      • 作用域
    • 📁词法语法和语义
      • 🗒️module
      • 💡严格模式
      • 🗒️词法
      • 🗒️自动插入分号
      • 🗒️预处理
      • 🗒️指令序言
    • 💡ECMAScript
    • 🗒️Q&A
      • 5.1 语言基础
      • 5.2 编程题
      • 5.3 DOM 相关
      • 5.4 其它
      • TODO
  • 浏览器 API
    • 🗒️DOM API
    • 🗒️Web Component
    • 🗒️History API
    • 🗒️客户端存储
    • 📁Fetch 规范
      • 3.2.1 概况
      • 3.2.2 Request 对象
      • 3.2.3 Response 对象
      • 3.2.4 Headers 对象
      • 3.2.5 fetch()
    • 🗒️HTTP
      • 3.1 HTTP 理论基础
      • 3.1 HTTP 理论
        • 3.1.2 HTTP Headers
        • CSP
    • 📁代码片段
      • 🗒️设置页面滚动条
      • 🗒️页面是否激活
      • 🗒️cookie 的读取
      • 🗒️WebSocket
      • 🗒️上传文件
      • 🗒️打点日志
    • 🗒️Q&A
      • 网络相关
      • TODO
  • web
    • 📁Web 安全
      • 💡概览
      • 🗒️XSS
      • 🗒️CSRF
      • ❕同源策略
      • ❕身份认证
      • ❕访问控制
    • 🗒️Web 性能
    • 🗒️Web 缓存
    • 💡Web 技术演化
      • 🗒️RESTful 设计风格
      • 🗒️GraphQL
  • 前端框架
    • 💡发展史
    • 🗒️MVVM
    • 💡Vue 简介
    • 📁Vue 组件
      • 💡简介
      • 🗒️Vue 指令
      • 🗒️逻辑复用
    • 📁Vue Router
      • 💡简介
      • 📁源码阅读
        • 1. 源码结构
        • 2. 入口文件
        • 3. createRouter()
        • 4. createWebHistory()
        • 5. createRouterMatcher()
    • 📁VueUse
      • 🗒️最佳实践
    • 📁Q&A
      • 🗒️Vue
      • 🗒️Vue Router
  • 工程化
    • 📁npm
      • 🗒️使用 npm
      • 🗒️贡献 package
      • 🗒️npm CLI 命令
      • 🗒️配置 npm
    • 📁webpack
      • 🗒️相关背景
      • 🗒️内部原理
      • 🗒️webpack 简介
      • 🗒️webpack 配置
      • 🗒️module
      • 🗒️plugins
    • 📁Vite
      • 🗒️Vue3 和 Vite
      • 🗒️Vue3 测试
    • 📁更多工具
      • 🗒️ssh
    • 🗒️Q&A
      • 5.1 工程化基础
      • TODO
  • 服务器端
    • 📁网站部署
      • 1.1 概况
    • 🗒️Node.js
  • 相关网站
    • 💡标准
    • 💡网站
    • 🧑个人博客
    • 🗒️工具
Powered by GitBook
On this page
  • 1. 普通语句
  • 表达式语句
  • 2. 语句块
  • 3. 控制型语句
  • 4. 带标签的语句
  • 5. 写在最后
  • 6. 参考
  1. JavaScript
  2. 运行时

语句的执行过程

整理的笔记,来源详见文末

Previous函数的执行过程NextProxy

Last updated 2 years ago

语句是任何编程语言的基础结构,比较常见的有变量声明、表达式、条件、循环等。与 JavaScript 对象一样,JavaScript 语句同样具有“看起来很像其它语言,但是其实一点都不一样”的特点。

JavaScript 语句的执行机制涉及一种基础类型:,它用于描述异常和跳出等语句执行过程。这一机制的基础正是 JavaScript 语句执行的完成状态,我们用一个标准类型来表示 Completion Record,它表示一个语句执行完之后的结果,有三个字段:

  • [[type]] 表示完成的类型,有 break, continue, return, throw 和 normal 几种类型

  • [[value]] 表示语句的返回值,如果语句没有,则是 empty

  • [[target]] 表示语句的目标,通常是一个 JavaScript 标签

JavaScript 正是依靠语句的 Completion Record 类型,来控制语句的执行过程,即便有复杂的嵌套。

1. 普通语句

在 JavaScript 中,普通语句就是不带控制能力的语句。它有以下几类:

  1. 声明类语句:var, const, let, function, class 声明

    • 声明类语句会响应预处理过程,其它普通语句只有执行过程

  2. 表达式语句

    • 只有表达式语句会产生 [[value]]

  3. 空语句

  4. debugger 语句

  5. with 语句(已废弃)

这些语句在执行时,是从前到后顺次执行的(先忽略 var 和函数声明的预处理机制),没有任何分支或重复执行的逻辑。普通语句执行后,会得到 [[type]] 为 normal 的 Completion Record,JavaScript 引擎会继续执行下一条语句。

表达式语句

普通语句中,只有表达式语句会产生 [[value]]。 我们常用的 Chrome 开发者工具,它控制台显示的就是语句的 Completion Record 的 [[value]]。

let score = 100; // 声明类语句,没 [[value]]
score = 99; // 表达式语句,会有 [[value]]

控制台的输入如下:

表达式语句实际上就是一个表达式,它是由运算符连接变量或者直接量构成的。

  1. Primary Expression,主要表达式。表达式的最小单位,它所涉及的语法结构也是优先级最高的

  2. MemberExpression,成员表达式。

  3. NewExpression,new 表达式。

  4. CallExpression,函数调用表达式。

  5. LeftHandSideExpression,左值表达式。

  6. AssignmentExpression,赋值表达式。

  7. Expression,表达式,用逗号运算符连接的赋值表达式。

  8. 表达式的右边部分

2. 语句块

语句块就是用 {} 括起来的一组语句,可以嵌套。

语句块本身并不复杂,需要注意的是,当语句块的内部语句的 Completion Record 的 [[type]] 不为 normal 时,会打断语句块后续的语句执行。

比如,这是一个内部为普通语句的语句块:

// 注释里是每条语句执行后的 Completion Record
{
  var i = 1; // normal, empty, empty
  i ++; // normal, 1, empty
  console.log(i) //normal, undefined, empty
} // normal, undefined, empty

当我们在第三行加入一条 return 语句时,整个语句块就变成了非 normal 的,它会打断语句块中后续语句的执行,以此保证非 normal 的完成类型可以穿透复杂的语句嵌套结构,从而产生控制效果。

{
  var i = 1; // normal, empty, empty
  return i; // return, 1, empty
  i ++; 
  console.log(i)
} // return, 1, empty

3. 控制型语句

控制型语句会对不同类型的 Completion Record 产生反应。

  1. 对内部产生影响的

    1. 条件语句:if, switch

    2. 循环语句:for, while

      • for, for...in, for...of, for-await-of

      • while, do-while

    3. try

      • try 部分用于标识捕获异常的代码段

      • catch 部分则用于捕获异常后做一些处理

      • finally 则是用于执行后做一些必须执行的清理工作

  2. 对外部产生影响的:continue, break, return, throw

    • 为了保证语义清晰,不建议用 throw 表达任何非异常逻辑

这两类控制型语句的配合,会产生控制代码执行顺序和执行逻辑的效果,这也是我们编程的主要工作。通常情况,我们熟悉的是 for/while + break/continue 和 try + throw 这样的组合。但是实际上,这两类是可以两两组合的。如下:

比如下面的两个示例:

function foo(){
  try{
    return 0; // return 语句生效了
  } catch(err) {
  } finally {
    console.log("a"); // finally 也会执行
  }
}

console.log(foo());
function foo(){
  try{
    return 0;
  } catch(err) {
  } finally {
    return 1; // 会覆盖 try 里的 return 值
  }
}

console.log(foo());

因为 finally 中的内容必须保证执行,所以 try/catch 执行完毕,即使得到的结果是非 normal 型的完成记录,也必须要执行 finally。而当 finally 执行也得到了非 normal 记录,则会使 finally 中的记录作为整个 try 结构的结果。

4. 带标签的语句

任何 JavaScript 语句都是可以加标签的,在语句前加冒号。

大部分时候,这个东西类似于注释,没有任何用处。唯一有作用的时候,是和 Completion Record(完成记录)类型中的 [[target]] 配合,用于跳出多层循环。比如:

outer: while(true) {
  inner: while(true) {
      break outer;
  }
}
console.log("finished")

break/continue 语句后,如果跟了关键字就会产生带 [[target]] 的完成记录。一旦完成记录带了 [[target]],那么只有拥有对应 label 的循环语句会消费它。

5. 写在最后

JavaScript 中语句的执行过程,是由 Completion Record 类型来控制的。

因为语句之间存在着嵌套关系,所以语句的执行过程实际上主要是在一个树形结构上进行的。 树形结构的每一个节点在执行后都会产生一条 Completion Record,然后根据语句的结构和 Completion Record,JavaScript 实现了各种分支和跳出逻辑。

6. 参考

📁
🗒️
Completion 类型
https://time.geekbang.org/column/article/83860