编程语言的词法结构是一套基本规则,规定了如何使用这门语言编写程序,规定了变量如何命名、注释的定界符、如何分隔程序的语句等

ECMAScript 源码文本会被从左到右扫描,并被转换为一系列的输入元素(Token),包括标识符、控制符、行终止符、注释和空白符

JavaScript 代码的文本

字符集

JavaScript 代码使用 Unicode 字符集

区分大小写

  • JavaScript 是区分大小写的语言
  • 而 HTML 和 CSS 并不区分大小写(尽管 XML 区分大小写)
  • 也就是说如果用 JavaScript 控制 HTML 属性时,对 HTML 来说 id 和 ID 没区别,但 JavaScript 有区别

空白字符

JavaScript 会忽略程序中标识(Token)之间的空格,多数情况下同样会忽略换行符。因此可以采用整齐、一致的缩进、空格等来形成统一的格式,从而提高代码的可读性

可打印字符在渲染时会产生输出,但空白字符不会。空白字符在有限程度上定义了文本的布局,如:

  • 空白
  • 换行
  • 中断彼此相邻的渲染字符的正常顺序

常见的识别为空格的空白字符

名称Unicode 转义序列转义符HTML/XML命名实体说明
水平制表符\u0009\t&Tab;<HT>
空格符\u0020普通空格
非中断空格符\u00A0&nbsp;&NonBreakingSpace;与空格相同,但不是可以断行的点
零宽空格\u200B&ZeroWidthSpace;<ZWSP>,不使用显式空格向文本处理系统指示单词边界
零宽非连接符\u200C&zwnj;<ZWNJ>,中断彼此相邻的字符关联
零宽连接器\u200D&zwj;<ZWJ>,使左右字符关联
非中断零宽空格\u2060&NoBreak;<WJ>,与零宽空格相同,但不是可以断行的点

常见的行终止符

名称Unicode 转义序列转义符HTML/XML 命名实体说明
换行符\u000A\n&NewLine;<LF>
垂直制表符\u000B\v<VT>
进纸符\u000C\f<FF>
回车符\u000D\r<CR>
下一行\u0085<NEL>
行分隔符\u2028<LS>
段落分割符\u2029<PS>

注释

注释不会被执行,是给阅读代码的人看的

可以添加注释来对代码进行解释、提高代码的可读性,或者将代码注释,以阻止其执行

单行注释

// 注释内容
 
// 可以独占一行
const a = 6 // 也可以放到代码行末

多行注释

/* 注释内容
注释内容
注释内容 */
 
const a = /* 可以在代码中间 */ 6

为了美观,常写成:

/**
 * 注释内容
 * 注释内容
 * 注释内容
 */

块级注释左部分 /* 会匹配第一个 */,所以下面案例都是会报错的:

// 1: 块级注释嵌套
/*
注释 1
/* 注释 1.1 */
 */
 
// 2: 正则表达式字面量
/*
var rm_a = /a*/.match(s);
*/

字面量

字面量,又名直接量(Literals)

// 空字面量
null
 
// 布尔字面量
true
false
 
// 数值字面量
123_000
0b10101
0o63
0x4f
1.6e5
 
// 字符串字面量
'foo'
"bar"
`foo-bar`
 
// 对象字面量
{ a: 'foo', b: 'bar', c: 42 }
 
// 数组字面量
[1954, 1974, 1990, 2014]
 
// 正则表达式字面量
/ab+c/g
/(?:)/

标识符

标识符:给变量、函数、函数形参、属性(对象的键)命名的字符序列

命名规则(必须遵守的硬性规定):

  • 由 26 个英文字母大小写、0-9、_ 或 $ 组成
  • 数字不可以开头
  • 不可以使用关键字和保留字,但能包含关键字和保留字
  • 严格区分大小写,长度无限制
  • 标识符不能包含空格

其实标识符中的字母也可以包含扩展的 ASCII 或 Unicode 字母字符,但不推荐

命名规范(建议遵守的软性要求):

  • 类名、构造函数名、组件名(Vue、React):大驼峰命名法,XxxYyyZzz
  • 变量名、函数名、形参名、属性名:小驼峰命名法,xxxYyyZzz
  • 常量名:所有字母都大写,多单词时每个单词用下划线连接,XXX_YYY_ZZZ
    • 这里的常量不是指 const 修饰,而是业务逻辑意义上的不变值,如:加载因子、配置数量
  • 文件名:
    • 组件(Vue、React):大驼峰命名法,XxxYyyZzz.js
    • 其他正常文件:最常见的是第一种,当然也有人使用第二三种
      • 小驼峰命名法:xxxYyyZzz.js
      • 中划线法:xxx-yyy-zzz.js
      • 下划线法:xxx_yyy_zzz.js

关键字和保留字

JavaScript 保留关键字

JavaScript 保留了一些标识符为自己所用(已经用到或以后扩展使用)

abstractargumentsbooleanbreakbyte
casecatchcharclassconst
continuedebuggerdefaultdeletedo
doubleelseenumevalexport
extendsfalsefinalfinallyfloat
forfunctiongotoifimplements
importininstanceofintinterface
letlongnativenewnull
packageprivateprotectedpublicreturn
shortstaticsuperswitchsynchronized
thisthrowthrowstransienttrue
trytypeofvarvoidvolatile
whilewithyield

JavaScript 对象、属性和方法

JavaScript 内置的对象、属性和方法名

ArrayDateevalfunctionhasOwnProperty
InfinityisFiniteisNaNisPrototypeOflength
MathNaNnameNumberObject
prototypeStringtoStringundefinedvalueOf

Java 保留关键字

JavaScript 经常与 Java 一起使用

getClassjavaJavaArrayjavaClassJavaObjectJavaPackage

window 保留关键字

浏览器运行时

alertallanchoranchorsarea
assignblurbuttoncheckboxclearInterval
clearTimeoutclientInformationcloseclosedconfirm
constructorcryptodecodeURIdecodeURIComponentdefaultStatus
documentelementelementsembedembeds
encodeURIencodeURIComponentescapeeventfileUpload
focusformformsframeinnerHeight
innerWidthlayerlayerslinklocation
mimeTypesnavigatenavigatorframesframeRate
hiddenhistoryimageimagesoffscreenBuffering
openopeneroptionouterHeightouterWidth
packagespageXOffsetpageYOffsetparentparseFloat
parseIntpasswordpkcs11pluginprompt
propertyIsEnumradioresetscreenXscreenY
scrollsecureselectselfsetInterval
setTimeoutstatussubmittainttext
textareatopunescapeuntaintwindow

HTML 事件句柄

onbluronclickonerroronfocus
onkeydownonkeypressonkeyuponmouseover
onloadonmouseuponmousedownonsubmit

Unicode

ECMAScript 要求支持 Unicode 字符集,Unicode 是 ASCII 和 Latin-1 的超集,支持地球上几乎所有在使用的语言

  • 因此在字符串和注释中可以使用任意 Unicode 字符
  • 但是考虑到可移植性和易于编辑,建议在标识符中只使用 ASCII 字母和数字

Unicode 转义序列

在有些计算机硬件和软件中,无法显示或输入 Unicode 字符全集,JavaScript 定义了一种特殊序列来代表任意 16 位 Unicode 内码。格式为 \u 其后跟随 4 个十六进制数,可以用于 JavaScript 字面量、正则表达式和标识符中(关键字除外)

const café = 1 // 使用 Unicode 字符定义一个变量
caf\u00e9      // => 1;使用转义序列访问这个变量
caf\u{e9}      // => 1;相同转义序列的另一种形式

JavaScript 早期版本只支持 4 位数字转义序列;带花括号的版本是 ES6 新增的,目的是更好地支持大于 16 位的 Unicode 码点,比如表情符号:

console.log('\u{1F600}') // 😀

Unicode 归一化

如果在程序中使用了非 ASCII 字符,那必须知道 Unicode 允许用多种编码方式表示同一个字符

如,字符串 'é'

  • 可以被编码为一个 Unicode 字符 \u00E9
  • 也可以被编码为一个常规 ASCII 字符 e 后跟一个重音组合标记 \u0301

这两种编码在文本编辑器中看起来完全相同,但它们的二进制编码不同,因此 JavaScript 认为它们不同,而这可能导致非常麻烦的问题:

const café = 1; // 'caf\u{e9}'
const café = 2; // 'cafe\u{301}'
café            // => 1
café            // => 2
  • Unicode 标准为所有字符定义了首选编码并规定了归一化例程,用于把文本转换为适合比较的规范形式
  • JavaScript 假定自己解释的源代码已经归一化,它自己不会执行任何归一化
  • 如果想在 JavaScript 程序中使用 Unicode 字符,应该保证使用自己的编辑器或其他工具对自己的源代码执行 Unicode 归一化,以防其中包含看起来一样但实际不同的标识符

分号

JavaScript 使用分号 ; 将语句分隔开,但并不严格要求分号

当有地方需要分号时,它会在背后悄悄地添加分号,这被称为自动分号插入(Automatic Semicolon Insertion)

自动分号插入(ASI)规则

在解析源代码的过程中,当发现这些特殊情况时,JavaScript 解析器会自动添加一个分号:

  1. 下一行是别的代码开始,打断了当前的代码
  2. 出现 } 时,会在其之前插入一个分号
  3. 到达源代码文件的结尾
  4. 当前行有 return 语句
  5. 当前行有 break 语句
  6. 当前行有 continue 语句
  7. 当前行有 throw 语句
  8. 当前行有 yieldyield* 语句

省略分号的注意点

一个新行如果以下面符号开头,需要在最前面手动加上分号:

  • (:小括号
  • [:方括号
  • /:正则表达式开头的斜杠
  • +:加号
  • -:减号

实际代码中,这几种情况颇为少见