基础设施

现行标准 — 最后更新

参与:
GitHub whatwg/infra新建议公开议题
在 Matrix 聊天
提交:
GitHub whatwg/infra/commits
此提交的快照
@infrastandard
测试:
web-platform-tests infra/持续工作
翻译 (非规范性)
日本語
简体中文

摘要

基础设施标准(Infra Standard)旨在定义标准制定所依赖的基础性概念。

目标

欢迎提出更多目标建议。

1. 用法

要在标题为 X 的文档中使用本标准,请写:

X 依赖于 Infra[Infra]

此外,强烈建议交叉引用所有相关术语,以避免歧义。

2. 约定

2.1. 一致性

所有断言、图示、示例和注释均为非规范性内容,所有明确标记为非规范性的章节也是非规范性的。其他所有内容均为规范性内容。

关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY" 和 "OPTIONAL" 的解释方式见 RFC 2119。[RFC2119]

这些关键词在小写时等价,并且不得出现在非规范性内容中。

这对 RFC 8174 属于有意违规,目的是提高可读性,并延续许多非 IETF 发布的 RFC 8174 之前文档中的长期做法。[RFC8174]

上述内容适用于本标准及所有使用本标准的文档。鼓励使用本标准的文档仅使用 "must"、"must not"、"should" 和 "may",并采用小写形式,因为这样通常更易读。

对于非规范性内容,可以使用 "strongly encouraged"、"strongly discouraged"、"encouraged"、"discouraged"、"can"、"cannot"、"could"、"could not"、"might" 和 "might not" 等表达。

2.2. 与其他规范的一致性

一般来说,规范会与多种其他规范交互并依赖于它们。在某些情况下,不同规范之间的冲突需求可能导致某一规范不得不违反其他规范的要求。当发生这种情况时,使用 Infra 标准的文档应将此类违规标注为有意违规,并说明违规原因。

上一节 § 2.1 一致性 记录了 Infra 针对 RFC 8174 的一次有意违规

2.3. 术语

当 "或"(or)一词既可能为包含“或”又可能为排他“或”时(例如,“if either width or height is zero”,如果宽或高有一个为零),其含义为包含“或”(即“或两者皆是”),除非特别指出为排他“或”(如“但不能两者都为真”)。


用户代理是指代表用户行动的任何软件实体,例如获取和呈现 Web 内容、协助最终用户与内容交互的浏览器等。在使用 Infra 标准的规范中,用户代理通常指实现该规范的客户端软件的一个实例。该客户端软件本身称为实现。 一个人在日常生活中可以使用许多不同的用户代理,例如通过配置一个实现来同时作为多个用户代理,如使用多个用户配置文件或实现的隐私浏览模式等。

如果某事被声明为实现自定义(implementation-defined),则具体细节由实现自定义的内容由实现决定。如无此类声明,则反之:实现必须遵循使用本标准的文档所规定的规则。

实现自定义的方式在 input 中插入 U+000A(LF)码点,以使每一行不超过 width 个码点。对于此要求,行由 input 的起始、末尾以及 U+000A(LF)分隔。

2.4. 隐私问题

使用 Infra 标准的文档中定义的某些功能,可能会以牺牲部分用户隐私换取用户便利。

通常,由于互联网的架构,用户可以通过其 IP 地址与其他用户区分开。IP 地址并不能完全对应某个用户;当用户在不同设备或网络间切换时,IP 地址会变化;同样,NAT 路由、代理服务器和共享计算机等也会导致表面上来自同一 IP 的数据包实际对应多个用户。洋葱路由(onion routing)等技术还能进一步匿名化请求,使一个用户在网络某节点的请求表现为来自网络的多个不同位置。[RFC791]

然而,用户请求所用的 IP 地址并不是唯一可能将这些请求相关联的机制。例如,Cookie 就是为此而设计的,也是 Web 上大多数会话功能的基础,这些功能使你可以登录拥有账号的网站。更广泛地说,任何缓存机制或共享状态(包括但不限于 HSTS、HTTP 缓存、连接分组、存储 API 等)都可能被滥用。[COOKIES] [RFC6797] [STORAGE]

还有一些更隐蔽的机制。用户系统的某些特征可用于将不同用户群体区分开。收集足够多的信息后,可以计算出用户浏览器的“数字指纹”,这比 IP 地址更能判断哪些请求来自同一用户。

以这种方式关联请求,尤其跨站点时,可能被用于恶意目的,例如政府将某人使用某站点获取驾车导航时的家庭住址与其在某些论坛的参与情况结合起来,以确定该人是否应该被剥夺投票权。

由于恶意目的可能极其恶劣,强烈建议用户代理实现者和规范作者尽量减少可能被用于指纹识别或跟踪用户的信息泄露。

不幸的是,正如本节第一段所述,有时出于功能考虑需要开放某些 API,这些 API 也容易被用于指纹识别和跟踪,所以不能一概封堵。例如,允许登录网站以特定身份发帖,必然要求可以识别来自同一用户的所有请求。更微妙的是,比如文本宽度信息对于许多涉及 canvas 绘制文本效果(如加边框等)都必不可少,但这也可能泄露可用于分组请求的信息(例如通过暴力枚举推测用户安装了哪些字体,而字体信息因人而异)。

(This is a tracking vector.) 在使用 Infra 标准的文档中,能被用作跟踪向量的功能会像本段一样标注。

平台上的其他特性也可能被用于同样目的,包括但不限于:

3. 算法

3.1. 一致性

算法及其步骤中以祈使句表达的要求(如“去除所有前导空格”或“返回 false”),应根据引入该算法或步骤时所用关键词(如“must”)来理解其含义。如果未使用此类关键词,则默认视为 must。

例如,若规范写道:

吃一个橙子,用户必须:

  1. 剥橙子的皮。
  2. 将橙子分成一片片。
  3. 吃掉橙子片。

这等价于:

吃一个橙子

  1. 用户必须剥橙子的皮。
  2. 用户必须将橙子分成一片片。
  3. 用户必须吃掉橙子片。

这里的关键词是“must”。

如果上述算法仅以“要吃一个橙子:”引入,含义不变,因默认即为 must。

以算法或具体步骤表达的一致性要求,可以以任何方式实现,只要最终结果等价即可。(这些算法本意是易于理解,而非高性能。)

性能很难做到绝对正确,因为它受用户感知、计算机架构以及随时间变化的输入类型影响。例如,JavaScript 引擎通常会针对标准化为单一算法的内容实现多种代码路径,以优化速度或内存消耗。将所有这些代码路径标准化几乎不可能,也无益于标准的长期生命力,因此性能应作为业界竞争领域。

3.2. 避免对算法输入的限制

使用 Infra 标准的文档通常不应对算法输入的大小、资源使用等施加具体限制。这有助于用户代理间的竞争,也避免限制未来的计算需求。

(This is a tracking vector.) 但用户代理可对本应不受约束的输入施加实现自定义限制。例如防止拒绝服务攻击、防止内存耗尽或绕过平台特定限制等。

全局资源限制可被用作资源耗尽攻击的侧信道,攻击者可通过观察受害应用是否达到全局限制来推断。若资源限制因硬件差异而显著不同,也可用于指纹识别用户代理。

一个允许创建内存位图的 API 可以规范为允许任意尺寸,或允许尺寸不超过 JavaScript 的 Number.MAX_SAFE_INTEGER。但实现可以选择对尺寸加以实现自定义(未规范)限制,而不是尝试分配巨量内存。

某编程语言可能未规定最大调用栈深度。但实现可以出于实际需要加以限制。

由于某些代码可能依赖具体的限制,为了互操作性,有时规定一个下限是有益的。这对未来发展无碍,也能让代码在更多用户代理下运行。

实现自定义的限制规定一个下限也有助于互操作性,即确保所有实现都能处理至少某个规模的输入。

3.3. 声明

算法名通常为动词短语,但有时会采用强调其独立性的名称,便于标准和读者更习惯地引用该算法。

后一类算法名称的例子包括“属性变更步骤”、“内部模块脚本图获取过程”和“重载决议算法”。

声明算法时应写明其名称、参数和返回类型,格式如下:

【算法名】,给定一个[type1] 参数1、一个[type2] 参数2,……,执行以下步骤。返回值为[返回类型]。

(对于非动词短语算法名,使用“要执行【算法名】……”。更复杂的参数声明格式见§ 3.4 参数。)

解析一个很棒的格式,给定一个字节序列 bytes,执行以下步骤。返回字符串或 null。

不返回值的算法可用更简洁的格式声明。即使有返回值,若返回类型易于从步骤推断,也可采用该格式:

【算法名】,给定[type1] 参数1、[type2] 参数2,……:

解析一个很棒的格式,给定字节序列 bytes

极短的算法可以用一句话声明和描述:

解析一个很棒的格式,给定字节序列 bytes,返回bytes同构解码后再ASCII 大写化的结果。

算法声明应包含参数类型,但若参数名足够明确,或上下文足够清楚,也可省略类型(如只对其他算法简单包装时)。

加载经典脚本,给定 url,返回用 url 和 "classic" 调用内部脚本加载算法的结果。

3.4. 参数

算法参数一般按§ 3.3 声明所述顺序列出。但也有更复杂的情况。

算法参数可以是可选的,声明算法时须予以说明,并置于所有必选参数之后。可选参数可设默认值,也可在算法体内判断参数是否给出。具体格式如下:

……一个可选[type] 参数……

……一个可选[type] 参数(默认值为[默认值])……

可选布尔参数必须指定默认值,且默认为 false。

导航至资源 resource,可选字符串 navigationType,可选布尔 exceptionsEnabled(默认为 false):

  1. ……
  2. 如果给定 navigationType,则对其进行相关操作。
  3. ……

调用带可选位置参数的算法时,可省略尾部可选参数。

对上述算法的调用形式如:

但无法仅为第三个(exceptionsEnabled)参数赋非默认值而不传第二个(navigationType);且最后一种调用对读者不直观,因为需要追溯参数顺序。请继续阅读下文解决办法!

可选命名参数(非位置参数)可提升调用处的清晰度和灵活性。这类参数应同时标记为变量和定义,并在调用处链接。

导航至资源 resource,可选字符串 navigationType,可选布尔 exceptionsEnabled(默认为 false):

  1. ……
  2. 如给定 navigationType,则对其进行相关操作。
  3. ……

调用形式如:

注意,在算法步骤中,参数值只是变量引用,不链接到参数声明;只有调用处才链接参数声明。

非可选的命名参数同样可以用上述方式标记并在调用处链接,有助于提升调用处的清晰度。

布尔参数无论是否可选,均建议使用命名参数,详见 The Pitfalls of Boolean Trap

另一种提升清晰度的方法是将相关值打包为结构体(struct),并作为参数传递,尤其适用于多算法共用同一组相关值的场景。

3.5. 变量

变量使用 “let” 声明,使用 “set” 修改。

list 为新的列表

  1. value 为 null。

  2. 如果 input字符串,则将 value 设为 input

  3. 否则,将 value 设为 inputUTF-8 解码后所得。

  4. 断言value字符串

activationTargetisActivationEvent 为 true 且 target 具有激活行为时的 target,否则为 null。

变量在声明前不得使用。变量具有块作用域。每个算法中变量不得重复声明。

可用多重赋值语法,将多个变量赋值为元组各项,即变量名用括号包裹并用逗号分隔。变量个数必须与元组项数一致。

  1. statusInstance 为状态(200,`OK`)。

  2. 令 (status, statusMessage) 为 statusInstance

statusstatusMessage 赋值也可分为两步,分别用索引或名称访问元组

3.6. 控制流

算法的控制流中,"return" 或 "throw" 的要求会终止当前语句所在的算法。"return" 可将给定值返回给调用者。"throw" 会让调用者自动重新抛出给定值,并终止调用者算法。调用者可用叙述捕获异常并执行其他操作。

3.7. 条件中止

有时需要在某个条件变为真时停止执行一系列步骤。

此时,应声明该系列步骤将在特定 condition 满足时中止(abort when)。这表明这些步骤应在每一步前插入一条判断 condition 的语句,若其为真,则跳过剩余步骤。

若算法如此设计,则后续步骤可标注为中止时(if aborted),即若前面某步因 abort when 条件为真而被跳过,则该步必须执行。

如下算法:

  1. result 为空列表

  2. 执行以下步骤,中止条件为用户点击“取消”按钮:

    1. 计算 π 的前一百万位,并追加result

    2. 计算 e 的前一百万位,并追加result

    3. 计算 φ 的前一百万位,并追加result

  3. 如中止追加 "未完成!" 到 result

等价于如下更冗长写法:

  1. result 为空列表

  2. 若用户未点击“取消”按钮:

    1. 计算 π 的前一百万位,并追加result

    2. 若用户未点击“取消”按钮:

      1. 计算 e 的前一百万位,并追加result

      2. 若用户未点击“取消”按钮,则计算 φ 的前一百万位,并追加result

  3. 若用户点击了“取消”按钮,则追加"未完成!"到 result

使用该结构时,实现允许在指定步骤期间而非每步前后检查 condition,只要最终结果不变即可。例如,上述例子中只要 result 在运算期间未被修改,用户代理可中断计算。

3.8. 条件语句

带条件语句的算法应使用 "if"、"then" 和 "otherwise" 关键词。

  1. value 为 null。

  2. 如果 input字符串,则将 value 设为 input

  3. 返回 value

一旦使用 "otherwise",就不再用 "then"。

  1. value 为 null。

  2. 如果 input字符串,则将 value 设为 input

  3. 否则,将 value 设为失败。

  4. 返回 value

  1. value 为 null。

  2. 如果 input字符串,则将 value 设为 input

  3. 否则,若 input字符串列表,则将 value 设为 input[0]。

  4. 否则,抛出 TypeError

  5. 返回 value

3.9. 循环

可用多种方式重复执行一组步骤直到满足某条件。

Infra 标准尚未穷尽所有迭代写法,如有需要请提 issue。

For each

列表(及其衍生物)和映射中定义。

While

指令在条件满足时重复执行一组步骤。

condition 为 "met" 时:

  1. ……

迭代流程可用 continue(继续)或 break(中断)控制。continue 会跳过本次迭代剩余步骤进入下一个元素,如无剩余元素则终止。break 则跳过本次及后续所有元素,终止迭代。

example列表 « 1, 2, 3, 4 »。下述叙述会对 1、2、3、4 依次执行 operation

  1. 对于每个 item 属于 example

    1. item 执行 operation

下述叙述会对 1、2、4 执行 operation,跳过 3。

  1. 对于每个 item 属于 example

    1. item 为 3,则continue
    2. item 执行 operation

下述叙述会对 1、2 执行 operation,跳过 3、4。

  1. 对于每个 item 属于 example

    1. item 为 3,则break
    2. item 执行 operation

3.10. 断言

为提升可读性,可在算法中添加断言,用于表达不变量。写法为“断言:”,后接必须为真的语句。若该语句为假,则表明使用 Infra 标准的文档存在问题,应予以报告和修正。

因断言永远为真,对实现无要求。

  1. x 为 "Aperture Science"。

  2. 断言x 等于 "Aperture Science"。

4. 基本数据类型

4.1. 空值(Nulls)

值 null 用于表示没有值。它可与 JavaScript 的 null 值互换使用。[ECMA-262]

element 为 null。

如果 input 是空字符串,则返回 null。

4.2. 布尔值(Booleans)

布尔值只能为 true 或 false。

elementSeen 为 false。

4.3. 数字

数字很复杂,请参见 issue #87。我们希望将来能够为类型和数学运算提供更多指导,欢迎贡献!


8位无符号整数是范围为 0 到 255(0 到 28 − 1,包括端点)的整数。

16位无符号整数是范围为 0 到 65535(0 到 216 − 1,包括端点)的整数。

32位无符号整数是范围为 0 到 4294967295(0 到 232 − 1,包括端点)的整数。

64位无符号整数是范围为 0 到 18446744073709551615(0 到 264 − 1,包括端点)的整数。

128位无符号整数是范围为 0 到 340282366920938463463374607431768211455(0 到 2128 − 1,包括端点)的整数。

IPv6 地址是128位无符号整数


8位有符号整数是范围为 −128 到 127(−27 到 27 − 1,包括端点)的整数。

16位有符号整数是范围为 −32768 到 32767(−215 到 215 − 1,包括端点)的整数。

32位有符号整数是范围为 −2147483648 到 2147483647(−231 到 231 − 1,包括端点)的整数。

64位有符号整数是范围为 −9223372036854775808 到 9223372036854775807(−263 到 263 − 1,包括端点)的整数。

4.4. 字节(Bytes)

字节(byte)是一组八位比特,表示为“0x”加两个ASCII 大写十六进制数字,范围为 0x00 到 0xFF,包括端点。字节值(value)就是其底层数字值。

0x40 是一个字节,其为 64。

ASCII 字节是指在 0x00(NUL)到 0x7F(DEL)范围内的字节。如示例所示,除 0x28 和 0x29 外,ASCII 字节可在括号中附带 ASCII format for Network Interchange 标准码表中的描述。[RFC20]

0x28 可写作 "(left parenthesis)",0x29 可写作 "(right parenthesis)"。

0x49 (I) 经UTF-8 解码后为码点 U+0049 (I)。

4.5. 字节序列(Byte sequences)

字节序列是由字节组成的序列,表示为空格分隔的一串字节。若字节在 0x20(空格)到 0x7E(~)范围内,也可写作字符串,但需用反引号而非引号,避免与实际字符串混淆。

0x48 0x49 也可写作 `HI`。

如 `Content-Type` 这样的头字段就是字节序列

若需将字符串转为字节序列,建议使用 Encoding 中的UTF-8 编码;极少数情况下可用同构编码[ENCODING]

字节序列长度即其所含字节数。

字节序列转小写(byte-lowercase),把字节序列中范围 0x41(A)到 0x5A(Z)的每个字节加 0x20。

字节序列转大写(byte-uppercase),把字节序列中范围 0x61(a)到 0x7A(z)的每个字节减 0x20。

字节序列 A字节序列转小写B字节序列转小写一致,则 AB大小写不敏感(byte-case-insensitive)匹配。


若下述步骤返回 true,则字节序列potentialPrefix字节序列input前缀(prefix)

  1. i 为 0。

  2. true:

    1. 如果 i 大于等于 potentialPrefix长度,则返回 true。

    2. 如果 i 大于等于 input长度,则返回 false。

    3. potentialPrefixBytepotentialPrefix 的第 i字节

    4. inputByteinput 的第 i字节

    5. potentialPrefixByte 不等于 inputByte,则返回 false。

    6. ii + 1。

"input 以……为前缀(starts with) potentialPrefix" 可作为 "potentialPrefixinput前缀" 的同义写法。

字节序列 a 小于(byte less than) 字节序列 b,当且仅当如下步骤返回 true:

  1. ba前缀,返回 false。

  2. ab前缀,返回 true。

  3. nab 第一个不同字节的最小索引。(必有此索引,因为两者互不为前缀。)

  4. a 的第 n 个字节小于 b 的第 n 个字节,返回 true。

  5. 返回 false。


同构解码字节序列 input,返回一个字符串,其码点长度等于 input长度,且每个码点的等于 input 的各字节值,顺序一致。

4.6. 码点(Code points)

码点指 Unicode 码点,表示为 "U+" 后跟四到六个ASCII 大写十六进制数字,范围是 U+0000 到 U+10FFFF(包括端点)。码点即其底层数字。

码点后可以跟其名称、在括号中的显示形式(如不是 U+0028 或 U+0029),或两者都跟。建议使用 Infra 标准的文档,在无法显示或为 U+0028/U+0029 时用其名称,否则为提升可读性用括号内的显示形式。

码点的名称定义在 Unicode 中,用ASCII 大写字母表示。[UNICODE]

渲染为 🤔 的码点表示为 U+1F914。

引用该码点时,可写作 "U+1F914 (🤔)" 以提供额外信息。文档也可写作 "U+1F914 THINKING FACE (🤔)",但略显冗长。

难以明确显示的码点,如 U+000A,可写作 "U+000A LF"。U+0029 可写作 "U+0029 RIGHT PARENTHESIS",即使能显示,以避免括号不匹配。

码点有时也被称为字符(character),有些场合前缀会用 "0x" 而非 "U+"。

前导代理项(leading surrogate)是指范围在 U+D800 至 U+DBFF(包括端点)的码点

尾随代理项(trailing surrogate)是范围在 U+DC00 至 U+DFFF(包括端点)的码点

代理项(surrogate)前导代理项尾随代理项

标量值(scalar value)是指不是代理项码点

非字符(noncharacter)是指在 U+FDD0 至 U+FDEF(包括端点),或等于 U+FFFE、U+FFFF、U+1FFFE、U+1FFFF、U+2FFFE、U+2FFFF、U+3FFFE、U+3FFFF、U+4FFFE、U+4FFFF、U+5FFFE、U+5FFFF、U+6FFFE、U+6FFFF、U+7FFFE、U+7FFFF、U+8FFFE、U+8FFFF、U+9FFFE、U+9FFFF、U+AFFFE、U+AFFFF、U+BFFFE、U+BFFFF、U+CFFFE、U+CFFFF、U+DFFFE、U+DFFFF、U+EFFFE、U+EFFFF、U+FFFFE、U+FFFFF、U+10FFFE 或 U+10FFFF 的码点

ASCII 码点是指范围 U+0000 NULL 到 U+007F DELETE(包括端点)的码点

ASCII 制表符或换行符为 U+0009 TAB、U+000A LF 或 U+000D CR。

ASCII 空白符为 U+0009 TAB、U+000A LF、U+000C FF、U+000D CR 或 U+0020 SPACE。

"Whitespace" 是物质名词。

XML、JSON 和部分 HTTP 规范在其空白符定义中排除了 U+000C FF:

除非规范仅涉及 XML/JSON/HTTP,否则为新特性建议使用 Infra 的ASCII 空白符定义。

C0 控制符是指范围 U+0000 NULL 到 U+001F INFORMATION SEPARATOR ONE(包括端点)的码点

C0 控制符或空格C0 控制符或 U+0020 SPACE。

控制符C0 控制符或范围 U+007F DELETE 到 U+009F APPLICATION PROGRAM COMMAND(包括端点)的码点

ASCII 数字是指范围 U+0030 (0) 到 U+0039 (9)(包括端点)的码点

ASCII 大写十六进制数字ASCII 数字或范围 U+0041 (A) 到 U+0046 (F)(包括端点)的码点

ASCII 小写十六进制数字ASCII 数字或范围 U+0061 (a) 到 U+0066 (f)(包括端点)的码点

ASCII 十六进制数字ASCII 大写十六进制数字ASCII 小写十六进制数字

ASCII 大写字母是范围 U+0041 (A) 到 U+005A (Z)(包括端点)的码点

ASCII 小写字母是范围 U+0061 (a) 到 U+007A (z)(包括端点)的码点

ASCII 字母ASCII 大写字母ASCII 小写字母

ASCII 字母数字ASCII 数字ASCII 字母

4.7. 字符串(Strings)

字符串是一组16 位无符号整数,也称为码元(code unit)字符串也称为JavaScript 字符串字符串使用双引号与等宽字体表示。

"Hello, world!" 是一个字符串。

这与Unicode中“码元”的定义不同,本规范特指 Unicode 16 位字符串的定义。[UNICODE]

字符串也可按 JavaScript 规范 The String Type 一节的定义,解释为包含码点[ECMA-262]

该转换过程会将代理对(surrogate pair)转换为对应的标量值,并将剩余的代理项映射为对应码点,即保持原样。

由码元 0xD83D、0xDCA9 和 0xD800 组成的字符串,按码点解释后为 U+1F4A9 和 U+D800 两个码点

字符串长度(length)是其包含的码元数。

字符串码点长度(code point length)是其包含的码点数。


为表达字符串对所含码点的特殊限制,本规范定义了ASCII 字符串同构字符串标量值字符串。在规范中使用这些类型有助于提升清晰性。

ASCII 字符串是所有码点均为ASCII 码点字符串

同构字符串是所有码点均在 U+0000 NULL 至 U+00FF(ÿ)范围内的字符串

标量值字符串是所有码点均为标量值字符串

标量值字符串适用于所有涉及 I/O 或需要UTF-8 编码的操作。


要将 字符串 转换标量值字符串,需将其中的任何 代理项(surrogates) 替换为 U+FFFD(�)。

被替换的代理项不会是代理对,因为解释为码点时已将代理对转为标量值

标量值字符串可隐式作为字符串使用,因为每个标量值字符串都是字符串。而字符串仅当不含代理项时可隐式用作标量值字符串,否则需执行转换

实现可能需根据实际字符串和标量值字符串的表示方式执行显式转换。出于性能和内存原因,实现通常会为字符串提供多种实现。


字符串 a 等于(is/identical to) 字符串 b,当且仅当二者码元序列完全一致。

除非另有说明,所有字符串比较均用is

这种字符串比较方式在 HTML 中曾称为“区分大小写”比较。is 比较不仅区分大小写,还区分码点的各种编码方式,如规范化形式或组合符顺序。即使在 Unicode 意义下视觉或规范等价的两字符串也可能不is

字符串 potentialPrefix码元前缀(code unit prefix),当且仅当如下步骤返回 true:

  1. i 为 0。

  2. true:

    1. 如果 i 大于等于 potentialPrefix长度,则返回 true。

    2. 如果 i 大于等于 input长度,则返回 false。

    3. potentialPrefixCodeUnitpotentialPrefix 的第 i码元

    4. inputCodeUnitinput 的第 i码元

    5. potentialPrefixCodeUnit 不等于 inputCodeUnit,则返回 false。

    6. ii + 1。

若上下文明确是码元(如字符串字面量只含 U+0020 SPACE 到 U+007E (~)),则 "input 以……为前缀(starts with) potentialPrefix" 可视为 "potentialPrefixinput码元前缀" 的同义说法。

若取值未知,建议显式表达:targetStringuserInput码元前缀。若为字面量,则可直接说:userInput "!" 开头。

字符串 potentialSuffix码元后缀(code unit suffix),当且仅当如下步骤返回 true:

  1. i 为 1。

  2. true:

    1. potentialSuffixIndexpotentialSuffix长度i

    2. inputIndexinput长度i

    3. potentialSuffixIndex < 0,则返回 true。

    4. inputIndex < 0,则返回 false。

    5. potentialSuffixCodeUnitpotentialSuffixIndex 处的码元

    6. inputCodeUnitinputIndex 处的码元

    7. potentialSuffixCodeUnit 不等于 inputCodeUnit,则返回 false。

    8. ii + 1。

若上下文明确为码元(如字符串字面量只含 U+0020 SPACE 到 U+007E (~)),则 "input 以……为后缀(ends with) potentialSuffix" 可用作 "potentialSuffixinput码元后缀" 的同义说法。

若取值未知,建议显式表达:targetStringdomain码元后缀。若为字面量,则可直接说:domain "." 结尾。


字符串 a 码元小于(code unit less than) 字符串 b,当且仅当如下步骤返回 true:

  1. ba码元前缀,则返回 false。

  2. ab码元前缀,则返回 true。

  3. nab 第一个码元不同的最小索引。(必有此索引,因为两者互不为前缀。)

  4. a 的第 n 个码元小于 b 的第 n 个码元,则返回 true。

  5. 返回 false。

此与 JavaScript 的 < 运算符和其 sort() 方法在字符串数组上的排序顺序一致。该顺序直接比较每个字符串的 16 位码元,因而高效且确定,但对由代理对组成的码点不符合任何实际字母表或字典顺序。[ECMA-262]

例如,U+FF5E FULLWIDTH TILDE (~) 的码点显然小于 U+1F600 (😀),但波浪号为单一码元 0xFF5E,笑脸为两个码元 0xD83D 和 0XDE00,因此笑脸 码元小于 波浪号。


码元子串(code unit substring),即 字符串 string 中从 start 起长度为 length 的子串,按如下步骤确定:

  1. 断言startlength 为非负数。

  2. 断言start + length 不大于 string长度

  3. result 为空字符串。

  4. 对于 i 属于 区间 [start, start + length),将 string 的第 i码元追加到 result

  5. 返回 result

按位置取码元子串(code unit substring by positions),即 字符串 stringstartend,等价于 start 起长度 endstart码元子串

至字符串结尾的码元子串,即 字符串 stringstart 到结尾,等价于从 startstring长度码元子串

在 "Hello world" 中,从 1 起长度为 3 的码元子串为 "ell",也可表示为从 1 到 4 的码元子串

这些算法中的数字应理解为码元之间的位置,而不是码元的索引。返回的子串是这两个位置间的码元。例如,空字符串内从 0 到 0 的码元子串仍为空字符串,即使该字符串并无索引 0 的码元。

码点子串(code point substring),即在字符串 string 中从 start 起长度为 length 的码点子串,按如下步骤确定:

  1. 断言startlength 为非负数。

  2. 断言start + length 不大于 string码点长度

  3. result 为空字符串。

  4. 对于 i 属于 区间 [start, start + length),将 string 的第 i码点追加到 result

  5. 返回 result

按位置取码点子串(code point substring by positions),即 字符串 stringstartend,等价于 start 起长度 endstart码点子串

至字符串结尾的码点子串,即 字符串 stringstart 到结尾,等价于从 startstring码点长度码点子串

一般情况下,开发者传入位置或长度时用码元子串,与 JavaScript 字符串索引方式一致。如 CharacterData 类的方法。[DOM]

其他场合更适合用码点子串。例如 "👽" 中从 0 起长度 1 的码点子串为 "👽",而同样位置的码元子串为只含单个代理项 U+D83B 的字符串。


同构编码(isomorphic encode)同构字符串 input:返回一个字节序列,其长度等于 input码点长度,各字节等于 input 的各码点值,顺序一致。


ASCII 小写化字符串,将该字符串中的所有ASCII 大写字母替换为对应的码点ASCII 小写字母

ASCII 大写化字符串,将该字符串中的所有ASCII 小写字母替换为对应的码点ASCII 大写字母

字符串 AASCII 小写化BASCII 小写化一致,则 AB ASCII 不区分大小写(ASCII case-insensitive)匹配。

ASCII 编码(ASCII encode)ASCII 字符串 input:返回 input同构编码

同构编码UTF-8 编码input 返回相同的字节序列

ASCII 解码(ASCII decode)字节序列 input,执行以下步骤:

  1. 断言input 内所有字节均为ASCII 字节

    注:此前置条件确保同构解码UTF-8 解码对该输入返回同一字符串

  2. 返回 input同构解码


去除换行符(strip newlines) 字符串中的 U+000A LF 和 U+000D CR 码点

规范化换行符(normalize newlines),将字符串中的每对 U+000D CR U+000A LF 码点替换为单个 U+000A LF 码点,再将剩余的 U+000D CR 码点替换为 U+000A LF 码点

去除首尾 ASCII 空白符,从字符串开头和结尾删除所有ASCII 空白符

去除并合并 ASCII 空白符,将字符串中任意连续多个ASCII 空白符替换为单个 U+0020 SPACE 码点,再去除首尾ASCII 空白符


收集一串满足条件的码点,从字符串 input 给定追踪算法位置的位置变量 position,重复如下:

  1. result 为空字符串

  2. position 未越过 input 结尾,且 position码点满足 condition 时:

    1. 将该码点追加到 result

    2. position 加 1。

  3. 返回 result

该算法除返回收集到的码点外,还会更新调用算法的位置变量

跳过 ASCII 空白符,在字符串 input 中,给定位置变量 position收集所有ASCII 空白符(结果丢弃,仅更新 position)。


严格分割字符串(strictly split a string) input,以 码点 delimiter 为分隔符:

  1. positioninput位置变量,初始指向开头。

  2. tokens字符串列表,初始为空。

  3. token收集所有不等于 delimiter 的码点所得的字符串,给定 position

  4. 追加 tokentokens

  5. position 未越过 input 结尾:

    1. 断言position 处的码点delimiter

    2. position 加 1。

    3. token收集所有不等于 delimiter 的码点所得的字符串,给定 position

    4. 追加 tokentokens

  6. 返回 tokens

此算法为“严格分割”,而后文的按 ASCII 空白符分割按逗号分割更宽松(对分隔符间空白符有特殊处理)。

按 ASCII 空白符分割字符串(split a string on ASCII whitespace) input

  1. positioninput位置变量,初始指向开头。

  2. tokens字符串的列表,初始为空。

  3. 跳过 ASCII 空白符

  4. position 未越过 input 结尾:

    1. token收集所有非ASCII 空白符码点所得字符串。

    2. 追加 tokentokens

    3. 跳过 ASCII 空白符

  5. 返回 tokens

按逗号分割字符串(split a string on commas) input

  1. positioninput位置变量,初始指向开头。

  2. tokens字符串的列表,初始为空。

  3. position 未越过 input 结尾:

    1. token收集所有非 U+002C (,) 码点所得字符串。

      token 可能为空字符串。

    2. 去除首尾 ASCII 空白符
    3. 追加 tokentokens

    4. position 未越过 input 结尾:

      1. 断言position 处的码点为 U+002C (,)

      2. position 加 1。

  4. 返回 tokens

串联(concatenate)字符串列表 list,可选分隔符 separator,执行如下步骤:

  1. list 为空,则返回空字符串。

  2. 如未给出 separator,则设为""。

  3. 返回一个字符串,其内容为 list各项,用 separator 依次分隔。

要序列化集合 set,返回其用 U+0020 SPACE 串联的结果。

4.8. 时间(Time)

表示时间时,使用 时刻(moment)时间段(duration)规范类型。创建和与 JavaScript 交换这些类型时,请遵循 High Resolution Time § 3 规范作者工具中的建议。[HR-TIME]

5. 数据结构(Data structures)

传统上,规范常用一些语义共识的、但具体边界模糊的规范层数据结构。这通常效果良好,但在边界情况(如迭代顺序、或向有序集合追加已包含的时)会引发歧义。对更复杂数据结构(如映射)的记法和表达也因此不统一。

本标准定义了一小组通用数据结构及其操作与表述方式,以便规范间统一表述。

5.1. 列表(Lists)

列表(list)是一种规范类型,包含一组有限且有序的项(item)

为方便记法,可用 « » 括起,逗号分隔各,表示列表。索引用方括号,基于0。除用于exists外,索引不可越界。

example列表 « "a", "b", "c", "a" »。则 example[1] 是字符串 "b"。

为记法方便,可用多重赋值,将多个变量赋为列表,形式为 « 变量1, 变量2, … »。变量数须等于列表长度,各变量赋值为对应项。

  1. value列表 « "a", "b", "c" »。

  2. 令 « a, b, c » 为 value

  3. 断言a 为 "a"。

  4. 断言b 为 "b"。

  5. 断言c 为 "c"。

列表内容不完全可控(如源自用户输入),多重赋值前应检查长度

  1. list长度不为 3,则返回失败。

  2. 令 « a, b, c » 为 list


向非有序集合列表追加(append)即将给定加到结尾。

向非有序集合列表 A 扩展(extend) B,等价于对 B 的每个追加A

  1. ghostbusters 为 « "Erin Gilbert", "Abby Yates" »。

  2. 扩展 ghostbusters,追加 « "Jillian Holtzmann", "Patty Tolan" »。

  3. 断言ghostbusters长度为 4。

  4. 断言ghostbusters[2] 为 "Jillian Holtzmann"。

向非有序集合列表前置(prepend)即将给定加到开头。

对非有序集合列表替换(replace)所有满足条件的项为指定,否则不操作。

如为有序集合,上述定义有调整,详见下文有序集合追加前置替换

列表或集合,插入(insert)项于指定索引前,若索引为0则为前置

列表或集合,移除(remove)所有满足条件的项,否则不操作。

移除 x列表 « x, y, z, x » 后,所得列表为 « y, z »。

移除所有以 "a" 开头的字符串,如列表 « "a", "b", "ab", "ba" »,结果为 « "b", "ba" »。

列表清空(empty)移除全部

列表若包含某,则称其包含(contain)该项。也可说 list[index] 存在(exists)

列表长度(size)为其中数。

列表为空当其长度为0。

列表取索引(get the indices)即返回区间 [0, 长度)。

列表或集合,迭代(iterate/for each)每项,写作 "对于 item 属于 list",随后对 item 操作。

列表克隆(clone) list,即新建同类型列表 clone,对 list 追加clone,顺序一致。

这为“浅克隆”,各本身不复制。

original有序集合 « "a", "b", "c" »。克隆 original 得新有序集合 clone,如在 clone 中用替换将 "a" 换为 "foo",结果为 « "foo", "b", "c" »,而 original[0] 仍为 "a"。

列表升序排序(sort in ascending order),给定小于算法 lessThanAlgo,新建列表 sorted,内容按 lessThanAlgo 升序。相等项保持原顺序。

列表降序排序(sort in descending order)同理,但为降序。

original列表 « (200, "OK"), (404, "Not Found"), (null, "OK") »。若比较规则为第二项码元小于,升序结果为 « (404, "Not Found"), (200, "OK"), (null, "OK") »。


列表类型源自 JavaScript 规范(大写为 List);此处简化描述并扩展了操作词汇。JavaScript 需 List 时可用此定义。[ECMA-262]

5.1.1. 栈(Stacks)

部分列表被指定为栈(stack)。栈本质上是列表,但操作时通常使用下列专用操作,而不用追加前置移除

压栈(push)即对其追加

弹栈(pop):若非空,则移除其最后一项并返回,否则返回空。

窥栈(peek):若非空,则返回其最后一项,否则返回空。

虽然列表,但不应对其使用for each,而应结合whilepop

5.1.2. 队列(Queues)

部分列表被指定为队列(queue)。队列本质上是列表,但操作时通常使用下列专用操作,而不用追加前置移除

队列入队(enqueue)即对其追加

队列出队(dequeue):若队列非空,则移除其第一项并返回,否则返回空。

虽然队列列表,但不应对其使用for each,而应结合whiledequeue

5.1.3. 集合(Sets)

部分列表被指定为有序集合(ordered set)。有序集合是列表,但其语义要求不含重复

Web 平台几乎总要求有序集合,以保证不同浏览器间枚举顺序一致。即使无须关注顺序,也仍用有序集合,实现可因顺序不可见而优化。

创建(create)一个集合,给定列表 input

  1. result 为空集合

  2. 遍历 input 各项 item追加result

  3. 返回 result

有序集合追加(append):若集合已包含该项,则无操作,否则执行列表追加

有序集合 A扩展(extend) B,即遍历 B 各项 item追加A

有序集合前置(prepend):若集合已包含该项,则无操作,否则执行列表前置

有序集合 set替换(replace) itemreplacement:如 set 包含 itemreplacement,则用 replacement 替换首个出现,并移除其它所有实例。

有序集合 « "a", "b", "c" » 中替换 "a" 为 "c",结果为 « "c", "b" »;在 « "c", "b", "a" » 中结果也为 « "c", "b" »。

有序集合 set 是另一有序集合 superset子集(subset)superset 相应是超集(superset)),当且仅当 set 的每项 item 均被 superset 包含

这意味着每个有序集合既是自身的 子集,也是 超集

集合 A 等于(equal)集合 B,当且仅当 AB 的子集AB 的超集

集合 AB交集(intersection),为新建集合 set,遍历 A 各项 item,如 B 包含 item,则追加set

集合 AB并集(union),为克隆 Aset,再遍历 B 各项 item追加set

集合 AB差集(difference),为新建集合 set,遍历 A 各项 item,如 B 不包含 item追加set


区间(the range) nm(含端点),新建有序集合,含 n 至 m 的所有整数,递增排序,前提是 mn

区间(the exclusive range) nm(不含 m),新建有序集合,含 n 至 m-1 的所有整数,递增排序,前提是 m > n。若 m = n,则为新建空集合。

对于 区间 1 到 4,遍历 n

5.2. 映射(Maps)

有序映射(ordered map),有时简称“映射(map)”,是一种规范类型,包含有限个有序的元组,每个元组由键(key)值(value)组成,且每个键唯一。每个这样的元组称为条目(entry)

有序集合一样,默认假定映射有序以确保实现之间的互操作性。

可用字面量记法表示有序映射,用 «[ ]» 括起,条目以 keyvalue 记法表示,条目间用逗号分隔。

example有序映射 «[ "a" → `x`, "b" → `y` ]»,则 example["a"] 为字节序列 `x`。


要在有序映射 map 中,给定 key 及可选 default获取条目值(get the value of an entry)

  1. map key 且给定 default,则返回 default

  2. 断言:map key

  3. 返回 map 中键为 key

也可用下标符号直接写 map[key] 获取值。若需默认值,可加短语 with default 及默认值。

map["test"]存在,则返回 map["test"]。

example有序映射 «[ "a" → "x", "b" → "y" ]»,则 example["a"] 等价于 example["a"] with default "z",即 "x"。example["c"] 会触发断言;example["c"] with default "z" 为 "z"。

要在有序映射设定条目值(set the value of an entry),若已含指定则更新,否则加到末尾。可直接写“设 map[key] 为 value”。

要在有序映射移除条目(remove an entry),即移除所有满足条件的条目,无则不操作。若条件为某键,亦可写“移除 map[key]”。

清空(clear)有序映射,即移除其所有条目。

有序映射含有指定键条目,即存在该键的条目。亦可写 map[key] exists

要获取有序映射键(get the keys),返回其所有键组成的新有序集合

要获取有序映射值(get the values),返回其所有值组成的新列表

有序映射长度(size)为其键集合的长度

有序映射为空(is empty)当其长度为0。

遍历(iterate/for each)有序映射 map,可写“对于 keyvalue 属于 map”,随后对 keyvalue 操作。

克隆(clone)有序映射 map,新建有序映射 clone,对每对 keyvalue clone[key] 为 value

这是“浅克隆”,键和值本身不克隆。

original 为有序映射 «[ "a" → «1, 2, 3», "b" → «» ]»。克隆 original 得新映射 clone,如设 clone["a"] 为 «-1, -2, -3»,则为 «[ "a" → «-1, -2, -3», "b" → «» ]»,original 不变。但对 clone["b"] 追加 4,会同时影响 original

升序排序(sort in ascending order)映射 map,给定小于算法 lessThanAlgo,新建映射 sorted,按 lessThanAlgo 比较条目升序。相等者保持原顺序。

降序排序(sort in descending order)映射 map,同理为降序。

5.3. 结构体(Structs)

结构体(struct)是一种规范类型,包含有限组项(item),每项有唯一且不可变的名称(name)。每个持有特定类型的值。

一个 email 是结构体(struct)示例,包含 local part(字符串)和 host主机)。

伪算法示例:

  1. email 为 local part 为 "hostmaster" 且 host 为 infra.example 的 email。

5.3.1. 元组(Tuples)

元组(tuple)结构体,其有顺序。为方便记法,可用括号括起、逗号分隔各的字面量写法。需上下文能推断各项名称,可在首次出现前说明元组名称。可用下标(0 起)访问某项,索引不得越界。

status 是元组(tuple)示例,包含 code(数字)和 text(字节序列)。

伪算法示例:

  1. statusInstance 为 status (200, `OK`)。
  2. statusInstance 设为 (301, `FOO BAR`)。
  3. 如果 statusInstance 的 code 为 404,则……

最后一步也可写作“如果 statusInstance[0] 为 404,则……”。若元组项无显式定义,可能更适合此写法。

并非所有结构体都是元组是有意为之。Infra 用户可能需在不破坏依赖的字面量写法下增加新项名,此时不宜用元组。

6. JSON

本节算法采用 JavaScript 规范的约定。[ECMA-262]

将 JSON 字符串解析为 JavaScript 值,给定字符串 string

  1. 返回 ? Call(%JSON.parse%, undefined, « string »)。

将 JSON 字节解析为 JavaScript 值,给定字节序列 bytes

  1. string 为对 bytes 执行 UTF-8 解码 的结果。[ENCODING]

  2. 返回 将 JSON 字符串解析为 JavaScript 值给定 string 的结果。

将 JavaScript 值序列化为 JSON 字符串,给定 JavaScript 值 value

  1. result 为 ? Call(%JSON.stringify%, undefined, « value »)。

    未传递额外参数给 %JSON.stringify%,结果字符串无多余空白。

  2. result 为 undefined,则抛出 TypeError

    value 不可表示为 JSON(如 undefined 或函数),会发生此情况。

  3. 断言result字符串

  4. 返回 result

将 JavaScript 值序列化为 JSON 字节,给定 JavaScript 值 value

  1. string将 JavaScript 值序列化为 JSON 字符串给定 value 的结果。

  2. 返回对 string 执行 UTF-8 编码 的结果。[ENCODING]


上述操作直接作用于 JavaScript 值;因此对象或数组依赖于特定JavaScript realm。标准中通常更便于在 JSON 与无 realm 依赖的映射列表字符串布尔、数字和 null 间转换。

将 JSON 字符串解析为 Infra 值,给定字符串 string

  1. jsValue 为 ? Call(%JSON.parse%, undefined, « string »)。

  2. 返回 将 JSON 派生 JavaScript 值转换为 Infra 值给定 jsValue 的结果。

将 JSON 字节解析为 Infra 值,给定字节序列 bytes

  1. string 为对 bytes 执行 UTF-8 解码 的结果。[ENCODING]

  2. 返回 将 JSON 字符串解析为 Infra 值给定 string 的结果。

将 JSON 派生 JavaScript 值转换为 Infra 值,给定 JavaScript 值 jsValue

  1. jsValuenull,或 布尔字符串数字,则返回 jsValue

  2. IsArray(jsValue) 为 true:

    1. result 为空列表

    2. length 为 ! ToLength(! Get(jsValue, "length"))。

    3. 遍历 区间 0 到 length − 1 的每个 index

      1. indexName 为 ! ToString(index)。

      2. jsValueAtIndex 为 ! Get(jsValue, indexName)。

      3. infraValueAtIndex将 JSON 派生 JavaScript 值转换为 Infra 值给定 jsValueAtIndex 的结果。

      4. 追加 infraValueAtIndexresult

    4. 返回 result

  3. result 为空有序映射

  4. 遍历 ! jsValue.[[OwnPropertyKeys]]() 的每个 key

    1. jsValueAtKey 为 ! Get(jsValue, key)。

    2. infraValueAtKey将 JSON 派生 JavaScript 值转换为 Infra 值给定 jsValueAtKey 的结果。

    3. result[key] 为 infraValueAtKey

  5. 返回 result

将 Infra 值序列化为 JSON 字符串,给定字符串布尔、数字、null、列表或以字符串为键的映射 value

  1. jsValue将 Infra 值转换为 JSON 兼容的 JavaScript 值给定 value 的结果。

  2. 返回 ! Call(%JSON.stringify%, undefined, « jsValue »)。

    未传递额外参数给 %JSON.stringify%,结果无多余空白。

将 Infra 值序列化为 JSON 字节,给定字符串布尔、数字、null、列表或以字符串为键的映射 value

  1. string将 Infra 值序列化为 JSON 字符串给定 value 的结果。

  2. 返回对 string 执行 UTF-8 编码 的结果。[ENCODING]

将 Infra 值转换为 JSON 兼容的 JavaScript 值,给定 value

  1. value字符串布尔、数字或 null,则返回 value

  2. value列表

    1. jsValue 为 ! ArrayCreate(0)。

    2. i 为 0。

    3. 遍历 value 的每个 listItem

      1. listItemJSValue将 Infra 值转换为 JSON 兼容的 JavaScript 值 给定 listItem 的结果。

      2. 执行 ! CreateDataPropertyOrThrow(jsValue, ! ToString(i), listItemJSValue)。

      3. i = i + 1。

    4. 返回 jsValue

  3. 断言:value映射

  4. jsValue 为 ! OrdinaryObjectCreate(null)。

  5. 遍历 value 的每组 mapKeymapValue

    1. 断言:mapKey字符串

    2. mapValueJSValue将 Infra 值转换为 JSON 兼容的 JavaScript 值 给定 mapValue 的结果。

    3. 执行 ! CreateDataPropertyOrThrow(jsValue, mapKey, mapValueJSValue)。

  6. 返回 jsValue

规范中通常不宜直接操作 JavaScript 值,应优先用将 Infra 值序列化为 JSON 字符串将 Infra 值序列化为 JSON 字节。如有特殊需求,请提交 issue讨论。

7. 宽容 base64(Forgiving base64)

宽容 base64 编码(forgiving-base64 encode)给定字节序列 data,对 data 应用 RFC 4648 第 4 节定义的 base64 算法并返回结果。[RFC4648]

该操作之所以命名为 宽容 base64 编码,是为与宽容 base64 解码对称;后者与 RFC 有区别,定义了某些输入的错误处理。

宽容 base64 解码(forgiving-base64 decode)给定字符串 data,执行如下步骤:

  1. 移除 data 中所有ASCII 空白符

  2. data码点长度能被 4 整除:

    1. data 以一个或两个 U+003D (=) 码点结尾,则将其移除。

  3. data码点长度除以 4 余 1,则返回失败。

  4. data 包含不属于下列之一的码点

    则返回失败。

  5. output 为空字节序列

  6. buffer 为可追加比特的空缓冲区。

  7. positiondata位置变量,初始指向开头。

  8. position 未越过 data 结尾时,重复:

    1. 在 RFC 4648 Table 1: The Base 64 Alphabet 的第二列中找到 position 指向的码点。令 n 为该行第一格的数字。[RFC4648]

    2. n 的六个比特(高位在前)追加到 buffer

    3. buffer 已积累 24 比特,则将其解释为 3 个 8 位大端整数。将这 3 个字节依次追加到 output,然后清空 buffer

    4. position 加 1。

  9. buffer 非空,其长度为 12 或 18 比特。若为 12 比特,丢弃后 4 位,余下 8 位按大端解释为一个 8 位整数;若为 18 比特,丢弃后 2 位,余下 16 位按大端解释为两个 8 位整数。将所得 1 或 2 字节依次追加到 output

    丢弃比特意味着如 "YQ" 和 "YR" 都还原为 `a`。

  10. 返回 output

8. 命名空间(Namespaces)

HTML 命名空间为 "http://www.w3.org/1999/xhtml"。

MathML 命名空间为 "http://www.w3.org/1998/Math/MathML"。

SVG 命名空间为 "http://www.w3.org/2000/svg"。

XLink 命名空间为 "http://www.w3.org/1999/xlink"。

XML 命名空间为 "http://www.w3.org/XML/1998/namespace"。

XMLNS 命名空间为 "http://www.w3.org/2000/xmlns/"。

致谢(Acknowledgments)

特别感谢 Addison Phillips, Andreu Botella, Aryeh Gregor, Ben Kelly, Chris Rebert, Daniel Ehrenberg, Dominic Farolino, Gabriel Pivovarov, Ian Hickson, Jakob Ackermann, Jake Archibald, Jeff Hodges, Jeffrey Yasskin, Jungkee Song, Leonid Vasilyev, Maciej Stachowiak, Malika Aubakirova, Martin Thomson, Michael™ Smith, Mike West, Mike Taylor, Ms2ger, Pavel "Al Arz" Kurochkin, Philip Jägenstedt, Rashaun "Snuggs" Stovall, Sergey Shekyan, Simon Pieters, Tab Atkins, Tobie Langel, triple-underscore, Wolf Lammen, 以及薛富侨 的支持!

本标准由 Anne van KesterenApple, annevk@annevk.nl)和 Domenic DenicolaGoogle, d@domenic.me)编写。

知识产权声明(Intellectual property rights)

版权所有 © WHATWG (Apple, Google, Mozilla, Microsoft)。本作品采用 知识共享署名 4.0 国际许可协议。如本标准部分内容被纳入源代码,则该部分按 BSD 3-Clause License 许可。

本标准为 Living Standard。如需专利审查版本,请参阅 Living Standard Review Draft

索引(Index)

本规范定义的术语(Terms defined by this specification)

引用自其他规范的术语(Terms defined by reference)

参考文献(References)

规范性引用(Normative References)

[ECMA-262]
ECMAScript Language Specification(ECMAScript 语言规范)。URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. Encoding Standard(编码标准)。Living Standard. URL: https://encoding.spec.whatwg.org/
[HR-TIME]
Yoav Weiss. High Resolution Time(高分辨率时间)。URL: https://w3c.github.io/hr-time/
[Infra]
Anne van Kesteren; Domenic Denicola. Infra Standard(Infra 标准)。Living Standard. URL: https://infra.spec.whatwg.org/
[RFC20]
V.G. Cerf. ASCII format for network interchange(ASCII 网络交换格式)。October 1969. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc20
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels(规范性用词)。March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC4648]
S. Josefsson. The Base16, Base32, and Base64 Data Encodings(Base16、Base32 和 Base64 数据编码)。October 2006. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc4648
[UNICODE]
The Unicode Standard(Unicode 标准)。URL: https://www.unicode.org/versions/latest/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard(Web IDL 标准)。Living Standard. URL: https://webidl.spec.whatwg.org/

补充性参考文献(Informative References)

[COOKIES]
A. Barth. HTTP State Management Mechanism(HTTP 状态管理机制)。 April 2011. Proposed Standard. URL: https://httpwg.org/specs/rfc6265.html
[DOM]
Anne van Kesteren. DOM Standard(DOM 标准)。Living Standard. URL: https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch Standard(Fetch 标准)。Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard(HTML 标准)。 Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC6797]
J. Hodges; C. Jackson; A. Barth. HTTP Strict Transport Security (HSTS)(HTTP 严格传输安全)。November 2012. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6797
[RFC791]
J. Postel. Internet Protocol(互联网协议)。September 1981. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc791
[RFC8174]
B. Leiba. Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words(RFC2119 关键字大小写歧义)。May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[RFC8259]
T. Bray, Ed.. The JavaScript Object Notation (JSON) Data Interchange Format(JavaScript 对象表示法(JSON)数据交换格式)。December 2017. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc8259
[STORAGE]
Anne van Kesteren. Storage Standard(Storage 标准)。Living Standard. URL: https://storage.spec.whatwg.org/
[URL]
Anne van Kesteren. URL Standard(URL 标准)。Living Standard. URL: https://url.spec.whatwg.org/
[XML]
Tim Bray; et al. Extensible Markup Language (XML) 1.0 (Fifth Edition)(可扩展标记语言(XML)1.0(第五版))。2008年11月26日. REC. URL: https://www.w3.org/TR/xml/