From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- .../reference/lexical_grammar/index.html | 572 +++++++++++++++++++++ 1 file changed, 572 insertions(+) create mode 100644 files/zh-cn/web/javascript/reference/lexical_grammar/index.html (limited to 'files/zh-cn/web/javascript/reference/lexical_grammar/index.html') diff --git a/files/zh-cn/web/javascript/reference/lexical_grammar/index.html b/files/zh-cn/web/javascript/reference/lexical_grammar/index.html new file mode 100644 index 0000000000..c862bf1e70 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/lexical_grammar/index.html @@ -0,0 +1,572 @@ +--- +title: 词法文法 +slug: Web/JavaScript/Reference/Lexical_grammar +tags: + - JavaScript + - Keyword + - Literal + - 关键字 + - 字面量 + - 直接量 + - 词法 + - 语法 +translation_of: Web/JavaScript/Reference/Lexical_grammar +--- +
{{JsSidebar("More")}}
+ +

这部分描述了JavaScript 的词法(lexical grammar)。ECMAScript 源码文本会被从左到右扫描,并被转换为一系列的输入元素,包括 token、控制符、行终止符、注释和空白符。ECMAScript 定义了一些关键字、字面量以及行尾分号补全的规则。

+ +

格式控制符

+ +

格式控制符用于控制对源码文本的解释,但是并不会显示出来。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
使用 Unicode 编码表示的格式控制符
代码点名称缩写说明
U+200C零宽度非结合子<ZWNJ>放置在一些经常会被当成连字的字符之间,用于将它们分别以独立形式显示(Wikipedia
U+200D零宽度结合子<ZWJ>放置在一些通常不会被标记为连字的字符之间,用于将这些字符以连字形式显示(Wikipedia
U+FEFF字节流方向标识<BOM>在脚本开头使用,除了将脚本标记为Unicode格式以外,还用来标记文本的字节流方向(Wikipedia
+ +

空白符

+ +

空白符提升了源码的可读性,并将标记 (tokens) 区分开。这些符号通常不影响源码的功能。通常可以用压缩器来移除源码中的空白,减少数据传输量。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
空白符
代码点名称缩写说明转义序列
U+0009制表符<HT>水平制表符\t
U+000B垂直制表符<VT>垂直制表符\v
U+000C分页符<FF>分页符(Wikipedia\f
U+0020空格<SP>空格
U+00A0无间断空格<NBSP>在该空格处不会换行
Others其他 Unicode 空白<USP>Wikipedia上对 Unicode 空白的介绍
+ +

行终止符

+ +

除了空白符之外,行终止符也可以提高源码的可读性。不同的是,行终止符可以影响 JavaScript 代码的执行。行终止符也会影响自动分号补全的执行。在正则表达式中,行终止符会被 \s 匹配。

+ +

在 ECMAScript 中,只有下列 Unicode 字符会被当成行终止符,其他的行终止符(比如 Next Line、NEL、U+0085 等)都会被当成空白符。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
行终止符
编码名称缩写说明转义序列
U+000A换行符<LF>在UNIX系统中起新行\n
U+000D回车符<CR>在 Commodore 和早期的 Mac 系统中起新行\r
U+2028行分隔符<LS>Wikipedia
U+2029段分隔符<PS>Wikipedia
+ +

注释

+ +

注释用来在源码中增加提示、笔记、建议、警告等信息,可以帮助阅读和理解源码。在调试时,可以用来将一段代码屏蔽掉,防止其运行。

+ +

在 JavaScript 中,有两种添加注释的方法。

+ +

第一种是单行注释(single-line comment),使用 //,会将该行中符号以后的文本都视为注释:

+ +
function comment() {
+  // 这是单行注释
+  console.log("Hello world!");
+}
+comment();
+
+ +

第二种是多行注释(multiple-line comment),使用 /* */ ,这种方式更加灵活:

+ +

比如,可以在单行内使用多行注释:

+ +
function comment() {
+  /* 单行注释 */
+  console.log("Hello world!");
+}
+comment();
+ +

也可以用来实现多行注释:

+ +
function comment() {
+  /* 多行注释,
+     直到终止符号才结束 */
+  console.log("Hello world!");
+}
+comment();
+ +

多行注释也可以用于行内注释,但这样会使代码可读性变差,所以要谨慎使用:

+ +
function comment(x) {
+  console.log("Hello " + x /* 引入x的值 */ + " !");
+}
+comment("world");
+ +

另外,块注释也可以用来屏蔽一段代码,只要将这段代码用块注释包裹起来就可以了:

+ +
function comment() {
+  /* console.log("Hello world!"); */
+}
+comment();
+ +

注释中的 console.log() 的调用始终无效。这种方式可以屏蔽任意多行的代码,也可以屏蔽一行代码的一部分。

+ +

Hashbang 注释

+ +

专门的第三个注释语法,hashbang 注释正在 ECMAScript 中标准化(参见 Hashbang 语法建议)。

+ +

Hashbang 注释的行为与单行(//)注释完全相同,但它以 #! 开头且仅在脚本或模块的绝对开头有效。还要注意,在 #! 之前不允许有任何类型的空格。注释由 #! 之后的所有字符组成直到第一行的末尾;只允许有一条这样的注释。

+ +

Hashbang 注释指定特定 JavaScript 解释器的路径要用于执行脚本。示例如下:

+ +
#!/usr/bin/env node
+
+console.log("Hello world");
+
+ +
+

注意:JavaScript 中的 hashbang 注释模仿 Unix 中的 shebangs,用于指定适当的解释器运行文件。

+
+ +
+

尽管在 hashbang 注释之前的 BOM 在浏览器中能工作,但不建议在具有 hashbang 的脚本中使用 BOM。当您尝试在 Unix/Linux 中运行脚本时,有 BOM 将不工作。因此,如果要直接从 shell 运行脚本,请使用没有 BOM 的 UTF-8。

+
+ +

您只能使用 #! 注释样式以指定 JavaScript 解释器。在所有其他情况下,只需使用 // 注释(或多行注释)。

+ +

关键字

+ +

ECMAScript 6 中的保留关键字

+ +
+ +
+ +

未来保留关键字

+ +

在 ECMAScript 规格中,这些关键字被当成关键字保留。目前它们没有特殊功能,但是在未来某个时间可能会加上。所以这些关键字不能当成标识符使用。这些关键字在严格模式和非严格模式中均不能使用。

+ + + +

以下关键字只在严格模式中被当成保留关键字:

+ +
+ +
+ + + +

以下关键字只在模块代码中被当成保留关键字:

+ + + +

之前标准中的保留关键字

+ +

这里是之前版本中的ECMAScript(1到3)中的保留关键字:

+ +
+ +
+ +

另外,直接量nulltruefalse同样不能被当成标识使用。

+ +

保留字的使用

+ +

事实上保留字是仅针对标识符(Identifier)的文法定义而言的(而不是标识符名(IdentifierName)的文法定义)。如 es5.github.com/#A.1中所描述的, 这些都是不排斥保留字的标识符名.

+ +
a.import
+a["import"]
+a = { import: "test" }.
+
+ +

另一方面,如下用法是不允许的。因为它是一个标识符,而标识符的文法定义是除保留字以外的标识符名。标识符用于函数声明式和函数表达式.

+ +
function import() {} // Illegal.
+ +

直接量

+ +

空直接量

+ +

更多信息可以参考null

+ +
null
+ +

布尔直接量

+ +

更多信息可以参考Boolean

+ +
true
+false
+ +

数值直接量

+ +

十进制

+ +
1234567890
+42
+
+// 谨慎使用 0 开头的数值:
+0888 // 转换为十进制 888
+0777 // 转换为八进制 777,十进制 511
+
+ +

请注意,十进制数值直接量可以以 0 开头,但是如果 0 以后的最高位比 8 小,数值将会被认为是八进制而不会报错。更多信息可以参考 {{bug(957513)}} 和 parseInt()

+ +

二进制

+ +

二进制表示为开头是0后接大写或小写的B(0b或者0B)。这是ECMAScript 6中的新语法,可以参考下面的浏览器兼容性表格。如果0b之后有除了0或1以外的数字,将会抛出SyntaxError:“Missing binary digits after 0b”。

+ +
var FLT_SIGNBIT  = 0b10000000000000000000000000000000; // 2147483648
+var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040
+var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607
+ +

八进制

+ +

八进制表示为开头是0后接大写或小写的O(0o0O)。这是ECMAScript 6中的新语法,可以参考下面的浏览器兼容性表格。如果有不在(01234567)中的数字,将会抛出SyntaxError:“Missing octal digits after 0o”。

+ +
var n = 0O755; // 493
+var m = 0o644; // 420
+
+// 用0开头也可以实现(请查看上方十进制有关部分)
+0755
+0644
+
+ +

十六进制

+ +

十六进制表示为开头是0后接大写或小写的X(0x0X)。如果有不在(0123456789ABCDEF)中的数字,将会抛出SyntaxError:“Identifier starts immediately after numeric literal”。

+ +
0xFFFFFFFFFFFFFFFFF // 295147905179352830000
+0x123456789ABCDEF   // 81985529216486900
+0XA                 // 10
+
+ +

对象直接量

+ +

更多信息可以参考 {{jsxref("Object")}} 和对象初始化器

+ +
var o = { a: "foo", b: "bar", c: 42 };
+
+// ES6中的简略表示方法
+var a = "foo", b = "bar", c = 42;
+var o = {a, b, c};
+// 不需要这样
+var o = { a: a, b: b, c: c };
+
+ +

数组直接量

+ +

更多信息可以参考 {{jsxref("Array")}}。

+ +
[1954, 1974, 1990, 2014]
+ +

字符串直接量

+ +
'foo'
+"bar"
+ +

十六进制转义序列

+ +
'\xA9' // "©"
+
+ +

Unicode 转义序列

+ +

Unicode 转义序列要求在\u之后至少有四个字符。

+ +
'\u00A9' // "©"
+ +

Unicode 编码转义

+ +

ECMAScript 6新增特性。使用Unicode编码转义,任何字符都可以被转义为十六进制编码。最高可以用到0x10FFFF。使用单纯的Unicode转义通常需要写成分开的两半以达到相同的效果。

+ +

可以参考{{jsxref("String.fromCodePoint()")}}和{{jsxref("String.prototype.codePointAt()")}}。

+ +
'\u{2F804}'
+
+// 使用单纯 Unicode 转义
+'\uD87E\uDC04'
+ +

正则表达式直接量

+ +

更多信息可以参考 RegExp

+ +
/ab+c/g
+
+// 一个空的正则表达式直接量
+// 必须有一个空的非捕获分组
+// 以避免被当成是行注释符号
+/(?:)/
+ +

模板直接量

+ +

更多信息可以参考template strings

+ +
`string text`
+
+`string text line 1
+ string text line 2`
+
+`string text ${expression} string text`
+
+tag `string text ${expression} string text`
+ +

自动分号补全

+ +

一些 JavaScript 语句必须用分号结束,所以会被自动分号补全 (ASI)影响:

+ + + +

ECMAScript 规格提到自动分号补全的三个规则

+ +

1. 当出现一个不允许的行终止符或“}”时,会在其之前插入一个分号。

+ +
{ 1 2 } 3
+
+// 将会被 ASI 转换为
+
+{ 1 2 ;} 3;
+ +

2. 当捕获到标识符输入流的结尾,并且无法将单个输入流转换为一个完整的程序时,将在结尾插入一个分号。

+ +

在下面这段中,由于在 b++ 之间出现了一个行终止符,所以 ++ 未被当成变量 b后置运算符

+ +
a = b
+++c
+
+// 将被 ASI 转换为
+
+a = b;
+++c;
+
+ +

3. 当语句中包含语法中的限制产品后跟一个行终止符的时候,将会在结尾插入一个分号。带“这里没有行终止符”规则的语句有:

+ + + +
return
+a + b
+
+// 将被 ASI 转换为
+
+return;
+a + b;
+
+ +

规格

+ + + + + + + + + + + + + + + + + + + + + + + + +
规格状态备注
{{SpecName('ES1')}}{{Spec2("ES1")}}初始定义
{{SpecName('ES5.1', '#sec-7', 'Lexical Conventions')}}{{Spec2('ES5.1')}}
{{SpecName('ES6', '#sec-ecmascript-language-lexical-grammar', 'Lexical Grammar')}}{{Spec2('ES6')}}增加:二进制和八进制数值直接量,Unicode 编码转义直接量、模板直接量
+ +

浏览器兼容性

+ + + +

{{Compat("javascript.grammar")}}

+ +

参见

+ + -- cgit v1.2.3-54-g00ecf