1)、概述
- JavaScript 源代码中的输入可以这样分类:
- WhiteSpace 空白字符
- LineTerminator 换行符
- Comment 注释
- Token 词
- IdentifierName 标识符名称,典型案例是我们使用的变量名,注意这里关键字也包含在内了。
- Punctuator 符号,我们使用的运算符和大括号等符号。
- NumericLiteral 数字直接量,就是我们写的数字。S
- tringLiteral 字符串直接量,就是我们用单引号或者双引号引起来的直接量。
- Template 字符串模板,用反引号` 括起来的直接量。
2)、空白符号 Whitespace
- 说起空白符号,想必给大家留下的印象就是空格,但是实际上,JavaScript 可以支持更多空白符号。
3)、换行符 LineTerminator
- JavaScript 中只提供了 4 种字符作为换行符。
- 其中,是 U+000A,就是最正常换行符,在字符串中的\n。
- 是 U+000D,这个字符真正意义上的“回车”,在字符串中是\r,在一部分 Windows 风格文本编辑器中,换行是两个字符\r\n。
- 是 U+2028,是 Unicode 中的行分隔符。
- 是 U+2029,是 Unicode 中的段落分隔符。大部分 LineTerminator 在被词法分析器扫描出之后,会被语法分析器丢弃,但是换行符会影响 JavaScript 的两个重要语法特性:自动插入分号和“no line terminator”规则。
4)、注释 Comment
- JavaScript 的注释分为单行注释和多行注释两种:
/* MultiLineCommentChars */
// SingleLineCommentChars
5)、标识符名称 IdentifierName
-
IdentifierName 可以以美元符“$”、下划线“_”或者 Unicode 字母开始,除了开始字符以外,IdentifierName 中还可以使用 Unicode 中的连接标记、数字、以及连接符号。
-
我在前面提到了,关键字也属于这个部分,在 JavaScript 中,关键字有:await break case catch class const continue debugger default delete do else export extends finally for function if import ininstance of new return super switch this throw try typeof var void while with yield
-
除了上述的内容之外,还有 1 个为了未来使用而保留的关键字:enum
-
在严格模式下, 有一些额外的为未来使用而保留的关键字:implements package protected interface private public
-
除了这些之外,NullLiteral(null)和 BooleanLiteral(true false)也是保留字,不能用于 Identifier。import ininstance of new return super switch this throw try typeof var void while with yield
6)、符号 Punctuator
- 因为前面提到的除法和正则问题, / 和 /= 两个运算符被拆分为 DivPunctuator,因为前面提到的字符串模板问题,}也被独立拆分。加在一起,所有符号为:{ ( ) [ ] . ... ; , < > <= >= == != === !== + - _ % ** ++ -- << >> >>> & | ^ ! ~ && || ? : = += -= _= %= **= <<= >>= >>>= &= |= ^= => / /= }
7)、数字直接量 NumericLiteral
- JavaScript 规范中规定的数字直接量可以支持四种写法:十进制数、二进制整数、八进制整数和十六进制整数;
- 十进制的 Number 可以带小数,小数点前后部分都可以省略,但是不能同时省略;
- 12.toString() 这时候 12. 会被当作省略了小数点后面部分的数字,而单独看成一个整体,所以我们要想让点单独成为一个 token,就要加入空格,这样写: 12 .toString()
8)、字符串直接量 StringLiteral
-
JavaScript 中的 StringLiteral 支持单引号和双引号两种写法。
-
" DoubleStringCharacters "
-
' SingleStringCharacters '
-
-
单双引号的区别仅仅在于写法,在双引号字符串直接量中,双引号必须转义,在单引号字符串直接量中,单引号必须转义。字符串中其他必须转义的字符是\和所有换行符。JavaScript 中支持四种转义形式,还有一种虽然标准没有定义,但是大部分实现都支持的八进制转义。第一种是单字符转义。 即一个反斜杠\后面跟一个字符这种形式。有特别意义的字符包括有 SingleEscapeCharacter 所定义的 9 种,见下表:除了这 9 种字符、数字、x 和 u 以及所有的换行符之外,其它字符经过\转义后都是自身。
9)、正则表达式直接量 RegularExpressionLiteral
- 正则表达式由 Body 和 Flags 两部分组成,
/RegularExpressionBody/g;
- 其中 Body 部分至少有一个字符,第一个字符不能是 (因为 / 跟多行注释有词法冲突)。
- 正则表达式有自己的语法规则,在词法阶段,仅会对它做简单解析。
- 正则表达式并非机械地见到/就停止,在正则表达式[ ]中的/就会被认为是普通字符。
10)、字符串模板 Template
-
从语法结构上,Template 是个整体,其中的 ${ } 是并列关系。
-
实际上,在 JavaScript 词法中,包含 ${ } 的 Template,是被拆开分析的,如:
a${b}c${d}e它在 JavaScript 中被认为是:a${b}c${d}e -
它被拆成了五个部分:
- `a${ 这个被称为模板头
- }c${ 被称为模板中段
- }e` 被称为模板尾
- b 和 d 都是普通标识符
-
实际上,这里的词法分析过程已经跟语法分析深度耦合了。