11 ECMAScript 语言:源文本

11.1 源文本

语法

SourceCharacter :: 任意 Unicode 码点

ECMAScript 源文本是一个 Unicode 码点序列。所有从 U+0000 到 U+10FFFF 的 Unicode 码点值,包括代理码点,只要被 ECMAScript 文法允许,都可 以出现在 ECMAScript 源文本中。用于存储和交换 ECMAScript 源文本的实际编码方式 与本规范无关。无论外部源文本使用何种编码,符合规范的 ECMAScript 实现都会像处理 一个等价的 SourceCharacter 值序列那样处理源文本,其中每个 SourceCharacter 都是一个 Unicode 码点。符合规范的 ECMAScript 实现不要求对源文本执行任何规范化, 也不要求表现得像它们执行了源文本规范化一样。

组合字符序列的各个组成部分会被视为单独的 Unicode 码点,尽管用户可能会将整 个序列视为一个单一字符。

Note

在字符串字面量、正则表达式字面量、模板字面量和标识符中,任何 Unicode 码点 也都可以使用显式表示码点数值的 Unicode 转义序列来表示。在注释内部,这样的转 义序列会被当作注释的一部分而实际上被忽略。

ECMAScript 在 Unicode 转义序列的行为上不同于 Java 编程语言。例如,在 Java 程序中,如果 Unicode 转义序列 \u000A 出现在单行注释中,它会被解释为一个行 终止符(Unicode 码点 U+000A 是 LINE FEED (LF)),因此下一个码点就不再属于该 注释。类似地,如果 Unicode 转义序列 \u000A 出现在 Java 程序的字符串字面量 中,它同样会被解释为一个行终止符,而行终止符不允许出现在字符串字面量中——必须 写成 \n 而不是 \u000A,才能使 LINE FEED (LF) 成为字符串字面量值的一部 分。在 ECMAScript 程序中,出现在注释中的 Unicode 转义序列永远不会被解释,因此 不可能促成注释的终结。类似地,出现在 ECMAScript 程序字符串字面量中的 Unicode 转义序列总是构成该字面量的一部分,绝不会被解释为行终止符,也不会被解释为可能 终止字符串字面量的码点。

11.1.1 Static Semantics: UTF16EncodeCodePoint ( cp )

The abstract operation UTF16EncodeCodePoint takes argument cp (一个 Unicode 码点) and returns 一个 String. It performs the following steps when called:

  1. 断言:0 ≤ cp ≤ 0x10FFFF。
  2. 如果 cp ≤ 0xFFFF,返回一个 String 值,该值由数值等于 cp 的码元构成。
  3. cu1 为一个码元,其数值为 floor((cp - 0x10000) / 0x400) + 0xD800。
  4. cu2 为一个码元,其数值为 ((cp - 0x10000) modulo 0x400) + 0xDC00。
  5. 返回 cu1cu2 的字符串串接结果。

11.1.2 Static Semantics: CodePointsToString ( text )

The abstract operation CodePointsToString takes argument text (一个 Unicode 码点序列) and returns 一个 String. 它将 text 转换为一个 String 值,如 6.1.4 中所述。 It performs the following steps when called:

  1. result 为空字符串。
  2. 对于 text 中的每个码点 cp,执行
    1. result 设为 resultUTF16EncodeCodePoint(cp) 的字符串串接结果。
  3. 返回 result

11.1.3 Static Semantics: UTF16SurrogatePairToCodePoint ( lead, trail )

The abstract operation UTF16SurrogatePairToCodePoint takes arguments lead (一个码元) and trail (一个码元) and returns 一个码点. 构成一个 UTF-16 代理对的两个码元会被转换为一个码点。 It performs the following steps when called:

  1. 断言:lead 是一个前导代理项,且 trail 是一个尾随代理项。
  2. cp 为 (lead - 0xD800) × 0x400 + (trail - 0xDC00) + 0x10000。
  3. 返回码点 cp

11.1.4 Static Semantics: CodePointAt ( string, position )

The abstract operation CodePointAt takes arguments string (一个 String) and position (一个非负整数) and returns 一个 Record,具有字段 [[CodePoint]](一个码点)、[[CodeUnitCount]](一个正整数)和 [[IsUnpairedSurrogate]](一个 Boolean). 它将 string 解释为一个 UTF-16 编码的码点序列,如 6.1.4 中所述,并从索引为 position 的码元开始读取一个单独的码点。 It performs the following steps when called:

  1. sizestring 的长度。
  2. 断言:position ≥ 0 且 position < size
  3. firststring 中索引为 position 的码元。
  4. cp 为一个码点,其数值等于 first 的数值。
  5. 如果 first 既不是前导代理项也不是尾随代理项,那么
    1. 返回 Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }。
  6. 如果 first 是一个尾随代理项,或者 position + 1 = size,那么
    1. 返回 Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }。
  7. secondstring 中索引为 position + 1 的码元。
  8. 如果 second 不是尾随代理项,那么
    1. 返回 Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }。
  9. cp 设为 UTF16SurrogatePairToCodePoint(first, second)。
  10. 返回 Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }。

11.1.5 Static Semantics: StringToCodePoints ( string )

The abstract operation StringToCodePoints takes argument string (一个 String) and returns 一个码点列表. 它返回将 string 按照 6.1.4 中所述解释为 UTF-16 编码 Unicode 文本后所得的 Unicode 码点序列。 It performs the following steps when called:

  1. codePoints 为一个新的空列表。
  2. sizestring 的长度。
  3. position 为 0。
  4. 重复,当 position < size 时,
    1. cpCodePointAt(string, position)。
    2. cp.[[CodePoint]] 追加到 codePoints
    3. position 设为 position + cp.[[CodeUnitCount]]
  5. 返回 codePoints

11.1.6 Static Semantics: ParseText ( sourceText, goalSymbol )

The abstract operation ParseText takes arguments sourceText (一个 String 或一个 Unicode 码点序列) and goalSymbol (ECMAScript 文法之一中的一个非终结符) and returns 一个 Parse Node 或一个非空的 SyntaxError 对象列表. It performs the following steps when called:

  1. 如果 sourceText 是一个 String,则将 sourceText 设为 StringToCodePoints(sourceText)。
  2. 尝试使用 goalSymbol 作为目标符号来解析 sourceText,并分析解析结果是否存在任何早期错误条件。解析和早期错误检测可以按照实现定义的方式交错进行。
  3. 如果解析成功且未发现早期错误,则返回解析所得语法树根部的 Parse Node(即 goalSymbol 的一个实例)。
  4. 返回一个由一个或多个 SyntaxError 对象构成的列表,用来表示解析错误和/或早期错误。如果存在多个解析错误或早期错误,则列表中错误对象的数量和顺序由实现定义,但至少必须存在一个。
Note 1

设想某段文本在某个位置具有一个早期错误,而在更靠后的某个位置还有一个语法错 误。一个先执行解析遍历、再执行早期错误遍历的实现,可能会报告该语法错误,并且 不再继续到早期错误遍历。一个将这两项活动交错进行的实现,可能会报告该早期错 误,并且不再继续查找语法错误。第三种实现则可能会报告这两种错误。所有这些行为 都是符合规范的。

Note 2

另见 17 条。

11.2 源代码的类型

ECMAScript 代码共有四种类型:

Note 1

函数代码通常以函数定义(15.2)、 箭头函数定义(15.3)、 方法定义(15.4)、 生成器函数定义(15.5)、 异步函数定义(15.8)、 异步生成器函数定义(15.6) 以及异步箭头函数(15.9) 的函数体形式提供。函数代码也来源于传给 Function 构造器20.2.1.1)、 GeneratorFunction 构造器27.3.1.1)、 AsyncFunction 构造器27.7.1.1) 和 AsyncGeneratorFunction 构造器27.4.1.1)的参数。

Note 2

BindingIdentifier 包含在函数代码中的实际效果是:对于函数体中包含 "use strict" 指令的函数,其名称对应的 BindingIdentifier 会应用严格模式代 码的早期错误规则,即使外围代码不是严格模式代码也是如此。

11.2.1 指令序言与 Use Strict 指令

指令序言 是在 FunctionBodyScriptBodyModuleBody 中,作为起始的 StatementListItemModuleItem 出现的最长 ExpressionStatement 序列, 并且该序列中的每个 ExpressionStatement 都完全由一个 StringLiteral 记号 后跟一个分号构成。分号可以显式出现,也可以通过自动分号插入 (12.10)插入。 指令序言可以是空序列。

Use Strict 指令指令序言中的一个 ExpressionStatement,其 StringLiteral 恰好是码点序列 "use strict"'use strict' 之一。Use Strict 指令不能包含 EscapeSequenceLineContinuation

一个指令序言可以包含多个 Use Strict 指令。不过,如果发生这种情况,实现可以 发出警告。

Note

指令序言中的 ExpressionStatement 会在对其所在产生式求值期间按正常方式 求值。实现可以为那些不是 Use Strict 指令、但出现在指令序言中的 ExpressionStatement 定义特定于实现的含义。如果存在适当的通知机制,那么当 实现遇到一个出现在指令序言中、既不是 Use Strict 指令也没有被实现赋予特定含义 的 ExpressionStatement 时,应当发出警告。

11.2.2 严格模式代码

ECMAScript 语法单元可以使用非受限或严格模式的语法和语义来处理 (4.3.2)。在以下情 况下,代码会被解释为严格模式代码

不是严格模式代码的 ECMAScript 代码称为 非严格代码

11.2.2.1 Static Semantics: IsStrict ( node )

The abstract operation IsStrict takes argument node (一个 Parse Node) and returns 一个 Boolean. It performs the following steps when called:

  1. 如果 node匹配的源文本严格模式代码,返回 true
  2. 返回 false

11.2.3 非 ECMAScript 函数

ECMAScript 实现可以支持对某些函数异质对象进行求值,这些对象的求值行为用宿 主定义的某种可执行代码形式表达,而非 ECMAScript 源文本。从会调用这类函数对象 或被这类函数对象调用的 ECMAScript 代码视角来看,一个函数对象是在 ECMAScript 代码中定义的,还是一个内建函数,是不可观察的。