ECMAScript 语言类型和规范类型

前言

ECMAScript标准是深入学习JavaScript原理最好的资料,没有其二。

通过增加对ECMAScript语言的理解,理解javascript现象后面的逻辑,提升个人编码能力。

欢迎关注和订阅专栏 重学前端-ECMAScript协议上篇

阅读建议

  • 了解 存在 语言类型 和规范类型
  • 知道 引用记录和环境记录的概念
  • 了解 完成记录

对应协议 第六章 Data Types and Values , 语言类型和规范类型。

语言类型即编程中常用的数据类型。

规范类型值可用于描述 ECMAScript 表达式计算的中间结果,但这些值不能作为对象的属性或 ECMAScript 语言变量的值存储。

ECMAScript 语言类型

就是Javascript 编程中常用的数据类型。

ECMAScript 语言类型包括 Undefined, Null, Boolean, String, Symbol, Number, BigInt, and Object。

有人会问,为什么是大写。 列个表格就清晰了

typof 操作符 呢,是取其值判断后返回一个值给开发者用的,这里面当然就有经典 null返回 obejct。

类型 备注 typeof 的值
Undefined Type 只有一个值,undefined "undefined"
Null Type 只有一个值,null "object"
Boolean Type 两个值, true 和 false "boolean"
String Type "string"
The Symbol Type "symbol"
Numeric Types Number and BigInt "number"
The Object Type "object"

ECMAScript规范类型

它们不一定对应于 ECMAScript 实现中的任何特定实体。规范类型值可用于描述 ECMAScript 表达式计算的中间结果,但这些值不能作为对象的属性或 ECMAScript 语言变量的值存储。

这些规范类型,你大概有个印象即可,当协议中出现,你大致能明白是什么意思即可。

必须了解 引用记录 类型,这会面会有单独的章节讲述:

规范类型表格

英文名 中文名 备注
Enum Specification Type 枚举类型 枚举是规范内部的值,不能从 ECMAScript 代码直接观察到。主要是为了清晰、精确地定义和描述规范中涉及的特定状态或类型。例如,完成记录Completion Record的[[Type]]字段可以取NORMAL、RETURN或THROW等值。
List and Record Specification Types 列表和记录 List Type:参数列表。用于在新表达式、函数调用和其他需要简单有序值列表的算法中解释参数列表。函数的 arguments 就是这玩意。 Record type:描述本规范算法中的数据聚合。 Record 类型值由一个或多个命名字段组成。每个字段的值都是 ECMAScript 语言值或规范值。字段名总是用双括号括起来,例如[[ Value ]]。类似typescript的Record。
Set and Relation Specification Types 集合与关系规范类型 集合(Set)类型用于在内存模型中解释无序元素的集合。它与ECMAScript中同名的集合类型是不同的。为了避免混淆,在本规范中,ECMAScript集合类型的实例始终被称为"Set对象"。Set类型值是元素的简单集合,其中任何元素都不重复出现。可以向集合中添加或移除元素。集合之间可以进行合并(联合)、交集或差集运算。简言之,这里讨论的"Set类型"是一种理论上的数据结构概念,用于规范文档内部的说明和理论模型,强调的是数学意义上的无序唯一元素集合。而"Set对象"则是ECMAScript语言中实际可使用的、具备相应API的内置对象,如添加元素(add)、删除元素(delete)、检查元素是否存在(has)等方法,以及集合的基本操作如并集、交集等,这些都是通过具体的方法调用来实现的。 Relation Specification Type: 用来描述对集合元素之间某种特定约束或联系的抽象概念。关系类型的值是由其值域中的值组成的有序对集合。例如,一个关于事件的关系就是一个事件的有序对集合。对于关系R和R值域中的两个值a和b,a R b是表示有序对(a, b)是R的一个成员的简写方式。
Completion Record Specification Type 完成记录 用于解释值和控制流的运行,例如执行控制的非本地传输的语句(break、continue、return和throw)的行为。
Reference Record Specification Type 引用记录 引用记录类型用于解释诸如delete、typeof、赋值运算符、super关键字和其他语言特性等运算符的行为。例如,在执行obj.prop = value;这样的赋值操作时,obj.prop就会生成一个引用记录,引用名称是prop。
Property Descriptor Specification Type 属性描述符 解释对象属性属性的操作和具体化。对应这开发者常说的数据属性描述符和访问器属性描述符。属性描述符是访问器类型,它应包含[[Get]]、[[Set]]、[[Enumerable]]和[[Configurable]]字段;如果是数据类型,则应包含[[Value]]、[[Writable]]、[[Enumerable]]和[[Configurable]]字段。
Environment Record Specification Type 环境记录 用于解释嵌套函数和块中的标志符解析行为。环境记录是ECMAScript引擎内部用于跟踪变量和函数绑定的一种机制,它维护了当前执行上下文中变量名与变量值之间的映射关系。 在涉及到作用域链、闭包等概念时,环境记录扮演了关键角色。在函数嵌套或代码块嵌套的情况下,环境记录会形成一个层次结构,确保正确的变量查找和生命周期管理。
Abstract Closure Specification Type 抽象闭包 一系列算法步骤及其相关联的值集合。抽象闭包是一种元值,可以通过类似于函数调用的方式来调用,例如 closure(arg1, arg2)。与抽象操作类似,调用抽象闭包会执行闭包描述的算法步骤。
Data Blocks 数据块 用于描述字节大小(8位)的数值的独特且可变的序列。字节值是0到255之间的包含区间内的整数。创建一个 Data Block 值,该值具有固定数量的字节,每个字节的初始值为0。驻留在内存中且可以从多个代理(agent)并发引用的数据块被指定为共享数据块(Shared Data Block)。
PrivateElement Specification Type 私有字段/方法/访问器 用于描述私有类字段、方法和访问器的一种Record类型。尽管不使用属性描述符(Property Descriptors)来直接定义私有元素,但私有字段的行为类似于不可配置、不可枚举、可写的数据属性,私有方法的行为类似于不可配置、不可枚举、不可写的(函数)数据属性,而私有访问器的行为则类似于不可配置、不可枚举的访问器属性
ClassFieldDefinition Record Specification Type 类字段定义类型 用于规范类的字段。类字段可以是数据属性(Data Properties)或访问器属性(Accessor Properties)。
Private Names 私有名称 用于描述一个全局唯一的值,这个值代表着类私有元素(字段、方法或访问器)的键。由于Private Name 的全局唯一性,它能确保类内部的私有成员不会在类外部被直接访问或修改,从而增强代码的安全性和封装性。
ClassStaticBlockDefinition Record Specification Type class静态初始化块. 用于封装类静态初始化块的可执行代码。具体看如下代码段

静态块:

vbnet 复制代码
js
复制代码
class MyClass {     
    static {         
         console.log('Static initialization block');        
         MyClass.staticProp = {};     
    } 
} 

前面提到了 Enum Specification Type 类似 TypeScript enum 类型, 简单了解一下 typescripe enum的实现原理。

ini 复制代码
javascript
复制代码
enum EnumCompletionRecordType {
    normal = 0,
    break = 1,
    continue = 3,
    return = 4,
    throw = 5
}

使用 tsc 转换为js代码

javascript 复制代码
javascript
复制代码
"use strict";
var EnumCompletionRecordType;
(function (EnumCompletionRecordType) {

    EnumCompletionRecordType[EnumCompletionRecordType["normal"] = 0] = "normal";
    EnumCompletionRecordType[EnumCompletionRecordType["break"] = 1] = "break";
    EnumCompletionRecordType[EnumCompletionRecordType["continue"] = 3] = "continue";
    EnumCompletionRecordType[EnumCompletionRecordType["return"] = 4] = "return";
    EnumCompletionRecordType[EnumCompletionRecordType["throw"] = 5] = "throw";
    
})(EnumCompletionRecordType || (EnumCompletionRecordType = {}));

再输出一下 EnumCompletionRecordType 最后值的结构

发生ts的枚举类型最后被转为一个对象, 有键和值的对应,也有值和键的对应关系。

符合ECMAScript的实现必须提供并支持本规范中描述的所有类型、值、对象、属性、函数以及程序的语法和语义。

Enum Specification Type

枚举类型。枚举(Enums)是规范内部的值,不能直接从ECMAScript代码中观察到。

在协议中都是枚举值都是大写字母。

比如完成记录的 [[Type]]字段

比如私有字段的 [[Kind]]字段

List and Record Specification Types

列表(List)类型用于说明在新建表达式、函数调用以及其它需要简单有序值序列的算法中,参数列表(参见13.3.8节)的求值过程。List类型值就是由各个独立值组成的简单有序序列。这些序列的长度可以任意。列表的元素可以通过0起始的索引随机访问。为了记号上的方便,可以使用类似数组的语法来访问List的元素。例如,arguments[2] 是说列表arguments中第3个元素的一种简写方式。

这是不是就是类数组了。

表示法:例如,<< 1, 2 >> 定义了一个列表值,它包含两个元素,每个元素都被初始化为特定的值。一个新空列表可以表示为 << >>.

例如对象转原始值描述:

记录(Record)类型用于描述本规范中算法内部的数据聚合。记录类型值由一个或多个命名字段组成。每个字段的值可以是ECMAScript语言值或规范值。字段名总是用双中括号包围,例如 [[Value]]

这意味着,在规范文档中,当提到诸如[[Value]]这样的表达时,它指的是记录类型中的一个特定字段,用于存储某种特定的信息或数据。这类表示法常用于ECMAScript规范文档中,以标准化和精确地描述语言内部的结构和操作,尽管在实际编写JavaScript代码时,我们并不会直接使用这样的双中括号语法来定义对象的属性。

其实这个和 TypeScript 的 Record 类型很相似,只不过

  1. 用于表示协议的数据
  2. 字段名总是用双中括号包围,例如 [[Value]]

比如函数对象

又比如完成记录:

Completion Record Specification Type

完成记录(Completion Record)被用来解释值在运行时的传播以及控制流的转移,例如那些执行非局部控制转移的语句(如breakcontinuereturnthrow)的行为。

大概的数据结构如下:

字段名 含义
[[Type]] NORMAL、BREAK、CONTINUE、RETURN 或 THROW 发生的完成类型
[[Value]] 任何值,除了完成记录 产生的值
[[Target]] 一个字符串或空 有向控制转移的目标标签。

[[Target]]有值的时候,一般出现在出现 label 的时候,比如

css 复制代码
javascript
复制代码
label: for (let i = 0; i < 10; i++) {
  if (i === 5) {
    break label1; // 跳出循环,跳转到 label
  }
  console.log(i);
}

以下是一些用于指代完成记录的简写术语:

英文名 中文 说明
normal completion 正常完成 指的是任何[[Type]]值为normal的完成记录。当函数执行到代码末尾而没有遇到return语句或其他中断执行的控制流语句。
break completion 中断完成 指的是任何[[Type]]值为break的完成记录。即break语句返回的完成记录。
continue completion 继续完成 指的是任何[[Type]]值为continue的完成记录。即continue语句返回的完成记录。
return completion 返回完成 指的是任何[[Type]]值为return的完成记录。即 return语句返回的完成记录。
throw completion 抛出完成 指的是任何[[Type]]值为throw的完成记录。即throw语句返回的完成记录。

还有两种特别的完成记录术语:

英文名 中文 说明
abrupt completion 突然完成 指的是任何[[Type]]值不是normal的完成记录。即 break completion,continue completion, return completion, throw completion中的一种。
a normal completion containing some type of value 包含某类型值的正常完成 指的是在其[[Value]]字段中具有该类型值的正常完成。

这里接下来要说的是 a normal completion containing some type of value 和 normal completion。

协议里有一段话,有红色标记的话,这里的 callable objects 指的就是函数对象,说 callable objects 在本协议中,只能返回 normal completion 或者 throw completion。

那这就很意思了,函数最后可以return 啊, 为什么不可以返回 return completion呢?

查看 return 语句 ReturnStatement执行, 其返回的确实是 [[Type]]为 RETURN的完成记录。

可还记得,是怎么识别或者区分是不是 callable objects的呢? 就是检查有没有 [[Call]]方法,实际调用也会执行这个 [[Call]]方法

再一起看看 callable objects 即 函数对象的 这个[[Call]]

其返回的是 either a normal completion containing an ECMAScript language value or a throw completion

所以这里返回 normal completion containing an ECMAScript language value

  • 并不是 [[Type]] 为 NORMAL 的 normal completion,
  • 而是[[Value]]字段中具有某类型值的 normal completion containing some type of value, 其 [[Type]]不限于 NORMAL。

是不是有点绕,但这么理解是更为合理的。

相关推荐
极客小俊34 分钟前
粘性定位Position:sticky属性是不是真的没用?
前端
云端看世界37 分钟前
ECMAScript 类型转换 下
前端·javascript
云端看世界39 分钟前
ECMAScript 运算符怪谈 下
前端·javascript
云端看世界40 分钟前
ECMAScript 函数对象实例化
前端·javascript
前端爆冲41 分钟前
基于vue和flex实现页面可配置组件顺序
前端·javascript·vue.js
云端看世界42 分钟前
ECMAScript 中的特异对象
前端·javascript
il44 分钟前
Deepdive into Tanstack Query - 2.1 QueryClient 基础
前端
_十六1 小时前
看完就懂!用最简单的方式带你了解 TypeScript 编译器原理
前端·typescript
Komorebi_99991 小时前
Axios 是一个基于 Promise 的 HTTP 客户端,可用于浏览器和 Node.js 环境。以下是它的一些主要作用
javascript·ajax
云端看世界1 小时前
ECMAScript 运算符怪谈 上
前端·javascript·ecmascript 6