词法文法

您正在阅读此内容的英文版本,因为该语系尚未翻译。 帮助我们翻译此文章吧!

这部分描述了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 规格中,这些关键字被当成关键字保留。目前它们没有特殊功能,但是在未来某个时间可能会加上。所以这些关键字不能当成标识符使用。这些关键字在严格模式和非严格模式中均不能使用。

  • enum

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

  • implements
  • interface
  • let
  • package
  • private
  • protected
  • public
  • static

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

  • await

之前标准中的保留关键字

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

  • abstract
  • boolean
  • byte
  • char
  • double
  • final
  • float
  • goto
  • int
  • long
  • native
  • short
  • synchronized
  • transient
  • volatile

另外,直接量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 957513parseInt()

二进制

二进制表示为开头是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

对象直接量

更多信息可以参考 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 };

数组直接量

更多信息可以参考 Array

[1954, 1974, 1990, 2014]

字符串直接量

'foo'
"bar"

十六进制转义序列

'\xA9' // "©"

Unicode 转义序列

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

'\u00A9' // "©"

Unicode 编码转义

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

可以参考String.fromCodePoint()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)影响:

  • 空语句
  • letconst、变量声明
  • importexport、模块定义
  • 表达式语句
  • debugger
  • continuebreakthrow
  • return

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

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

{ 1 2 } 3 

// 将会被 ASI 转换为 

{ 1 2 ;} 3;

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

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

a = b
++c

// 将被 ASI 转换为

a = b;
++c;

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

  • 后置运算符(++--
  • continue
  • break
  • return
  • yieldyield*
  • module
return
a + b

// 将被 ASI 转换为

return;
a + b;

规格

规格 状态 备注
ECMAScript 1st Edition (ECMA-262) Standard 初始定义
ECMAScript 5.1 (ECMA-262)
Lexical Conventions
Standard
ECMAScript 2015 (6th Edition, ECMA-262)
Lexical Grammar
Standard 增加:二进制和八进制数值直接量,Unicode 编码转义直接量、模板直接量

浏览器兼容性

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
Array literals ([1, 2, 3])Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 4Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Binary numeric literals (0b)Chrome Full support 41Edge Full support 12Firefox Full support 25IE No support NoOpera Full support 28Safari Full support 9WebView Android Full support 41Chrome Android Full support 41Firefox Android Full support 25Opera Android Full support 28Safari iOS Full support YesSamsung Internet Android Full support 4.0nodejs Full support 4.0.0
Full support 4.0.0
Full support 0.12
Disabled
Disabled From version 0.12: this feature is behind the --harmony runtime flag.
Boolean literals (true/false)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Decimal numeric literals (1234567890)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Hashbang (#!) comment syntax
Experimental
Chrome Full support 74Edge No support NoFirefox Full support 67IE No support NoOpera ? Safari ? WebView Android Full support 74Chrome Android Full support 74Firefox Android Full support 67Opera Android ? Safari iOS ? Samsung Internet Android No support Nonodejs Full support Yes
Hexadecimal escape sequences ('\0xA9')Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 4Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Hexadecimal numeric literals (0xAF)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Null literal (null)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Numeric separators (1_000_000_000_000)Chrome Full support 75Edge No support NoFirefox Full support 70IE No support NoOpera Full support 62Safari ? WebView Android Full support 75Chrome Android Full support 75Firefox Android No support NoOpera Android No support NoSafari iOS ? Samsung Internet Android No support Nonodejs Full support Yes
Octal numeric literals (0o)Chrome Full support 41Edge Full support 12Firefox Full support 25IE No support NoOpera Full support 28Safari Full support 9WebView Android Full support 41Chrome Android Full support 41Firefox Android Full support 25Opera Android Full support 28Safari iOS Full support YesSamsung Internet Android Full support 4.0nodejs Full support Yes
Regular expression literals (/ab+c/g)Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 4Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
String literals ('Hello world')Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 3Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Unicode escape sequences ('\u00A9')Chrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 4Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes
Unicode point escapes (\u{})Chrome Full support 44Edge Full support 12Firefox Full support 40IE No support NoOpera Full support 31Safari Full support 9WebView Android Full support 44Chrome Android Full support 44Firefox Android Full support 40Opera Android Full support 32Safari iOS ? Samsung Internet Android Full support 4.0nodejs Full support Yes
Shorthand notation for object literalsChrome Full support 43Edge Full support 12Firefox Full support 33IE No support NoOpera Full support 30Safari Full support 9WebView Android Full support 43Chrome Android Full support 43Firefox Android Full support 33Opera Android Full support 30Safari iOS ? Samsung Internet Android Full support 4.0nodejs Full support Yes
Template literalsChrome Full support 41Edge Full support 12Firefox Full support 34IE No support NoOpera Full support 28Safari Full support 9WebView Android Full support 41Chrome Android Full support 41Firefox Android Full support 34Opera Android Full support 28Safari iOS Full support 9Samsung Internet Android Full support 4.0nodejs Full support 4.0.0
Trailing commasChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 9Opera Full support YesSafari Full support YesWebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0nodejs Full support Yes

Legend

Full support  
Full support
No support  
No support
Compatibility unknown  
Compatibility unknown
Experimental. Expect behavior to change in the future.
Experimental. Expect behavior to change in the future.
User must explicitly enable this feature.
User must explicitly enable this feature.

参见