JavaScript 基础语法——词法结构:从字符到代码的基石
JavaScript(简称 JS)作为 Web 开发的基石语言,其语法规则决定了代码如何被解析和执行。而词法结构(Lexical Structure) 是语法的基础,它定义了 JavaScript 代码的基本“积木”——包括字符编码、大小写规则、空格处理、注释、标识符、关键字、字面量、运算符等。理解词法结构是写出正确、可维护代码的第一步,也是排查语法错误的关键。本文将系统梳理 JavaScript 词法结构的核心内容,结合实例和最佳实践,帮助读者夯实基础。
目录#
1. 字符与编码#
JavaScript 代码由字符组成,其字符集基于 Unicode 标准(可表示世界上几乎所有语言的字符)。具体来说:
- 编码格式:JS 引擎通常使用 UTF-8 编码解析代码(兼容 ASCII),支持多字节字符(如中文、日文、emoji 等)。
- 字符范围:除了常规的字母、数字、符号,还支持 Unicode 转义序列(如
\u00A9表示版权符号 ©)。
示例:Unicode 字符在代码中的使用#
// 变量名包含中文(合法但不推荐,见最佳实践)
let 用户名 = "张三";
console.log(用户名); // 输出:张三
// 使用 emoji 作为变量名(合法但不推荐)
const 😊 = "笑脸";
console.log(😊); // 输出:笑脸
// Unicode 转义序列
const copyright = "\u00A9 2024";
console.log(copyright); // 输出:© 2024最佳实践:#
- 优先使用 ASCII 字符:尽管 JS 支持 Unicode 标识符,但非 ASCII 字符可能降低代码可读性(尤其团队协作时),且部分编辑器或工具可能不兼容。
- 避免特殊符号:除非必要(如
$用于框架变量,如 jQuery 的$),否则变量名尽量使用字母、数字、_和$。
2. 大小写敏感性#
JavaScript 是大小写敏感(Case-Sensitive) 的语言,即同一字符的大小写被视为不同的符号。
示例:大小写差异导致的变量区分#
let name = "Alice";
let Name = "Bob";
let NAME = "Charlie";
console.log(name); // 输出:Alice(小写)
console.log(Name); // 输出:Bob(首字母大写)
console.log(NAME); // 输出:Charlie(全大写)常见陷阱:#
- 关键字大小写错误:如
If(错误) vsif(正确),Function(错误) vsfunction(正确)。 - API 方法大小写:如
console.log不可写成console.Log。
最佳实践:#
- 严格区分大小写:养成变量、函数名大小写一致的习惯,避免因拼写错误导致的 BUG。
- 遵循命名规范:如变量用
camelCase(小驼峰)、构造函数用PascalCase(大驼峰)、常量用UPPER_SNAKE_CASE(全大写+下划线)。
3. 空白符与行终止符#
空白符(Whitespace)和行终止符(Line Terminators)用于分隔代码元素,增强可读性,但 JS 引擎会忽略多余的空白。
空白符类型:#
- 空格(
)、制表符(\t)、垂直制表符(\v)、换页符(\f)。 - 行终止符:换行符(
\n)、回车符(\r)、回车+换行(\r\n)、行分隔符(\u2028)、段落分隔符(\u2029)。
示例:空白符的作用#
// 以下代码等效,空白符不影响执行
let a=1;let b=2;console.log(a+b);
let a = 1;
let b = 2;
console.log(a + b); // 输出:3(可读性更佳)注意事项:#
- 行终止符可能触发 ASI(见第 8 节):部分场景下,换行可能被 JS 引擎解释为分号。
- 空白符不能出现在标识符中间:如
user name(错误),需用userName或user_name。
最佳实践:#
- 统一缩进:使用 2 或 4 个空格(避免混合空格和制表符),提升代码可读性。
- 合理换行:长代码行(如超过 80-120 字符)应换行,保持代码整洁。
4. 注释#
注释用于解释代码逻辑,不参与执行。JS 支持两种注释方式:
4.1 单行注释(//)#
以 // 开头,注释范围从 // 到行尾。
// 这是单行注释
let age = 18; // 年龄变量(行内注释)4.2 多行注释(/* */)#
以 /* 开头,*/ 结尾,可跨多行。
/*
这是多行注释
用于描述复杂逻辑
*/
function add(a, b) {
return a + b;
}最佳实践:#
- 注释“为什么”而非“是什么”:代码本身应清晰表达“做什么”,注释需解释“为什么这么做”(如业务逻辑、特殊处理的原因)。
- 避免过时注释:代码更新时同步更新注释,否则注释会误导读者。
- 禁用注释掉的代码:废弃代码应直接删除,而非注释保留(版本控制工具如 Git 可追溯历史)。
5. 标识符与保留字#
标识符(Identifier) 是用于命名变量、函数、类、属性等的名称。保留字(Reserved Words) 是 JS 预留的关键字,不能用作标识符。
5.1 标识符命名规则:#
- 必须以 字母(
a-z、A-Z)、下划线(_)或 美元符号($)开头。 - 后续字符可包含字母、数字(
0-9)、_或$。 - 不能包含空格、标点符号(除
_和$)。 - 区分大小写(如
age和Age是不同标识符)。
示例:合法与非法标识符#
// 合法标识符
let userName;
let _privateVar;
let $total;
let count123;
// 非法标识符(会报错)
let 123var; // 以数字开头
let user-name; // 包含连字符
let if; // 是保留字
let my name; // 包含空格5.2 保留字#
JS 保留字分为 关键字(如 if、function)、未来保留字(如 class、enum)和 严格模式保留字(如 implements、package)。部分保留字在非严格模式下可作为标识符,但强烈不推荐。
常见关键字:break、case、catch、class、const、continue、debugger、default、delete、do、else、export、extends、finally、for、function、if、import、in、instanceof、new、return、super、switch、this、throw、try、typeof、var、void、while、with、yield。
最佳实践:#
- 见名知意:标识符名称应清晰表达其含义(如
userAge而非ua)。 - 遵循命名规范:
- 变量/函数:
camelCase(如calculateTotal)。 - 类/构造函数:
PascalCase(如UserAccount)。 - 常量:
UPPER_SNAKE_CASE(如MAX_RETRY_COUNT)。 - 私有成员(约定):前缀
_(如_internalMethod)。
- 变量/函数:
6. 字面量(Literals)#
字面量是直接在代码中表示的值,是 JS 数据类型的直接体现。常见字面量类型如下:
6.1 数字字面量#
表示数值,支持整数、浮点数、十六进制、八进制、二进制和 BigInt。
// 十进制整数
let intNum = 42;
// 浮点数
let floatNum = 3.14;
// 科学计数法
let sciNum = 1e3; // 1000(1 × 10³)
let sciNum2 = 2e-2; // 0.02(2 × 10⁻²)
// 十六进制(前缀 0x)
let hexNum = 0xFF; // 255
// 二进制(前缀 0b)
let binNum = 0b1010; // 10
// 八进制(前缀 0o)
let octNum = 0o17; // 15(十进制)
// BigInt(后缀 n,用于超大型整数)
let bigNum = 9007199254740993n;6.2 字符串字面量#
表示文本,支持单引号(')、双引号(")和模板字面量( )。
// 单引号/双引号(功能相同,选一种保持一致)
let str1 = 'Hello';
let str2 = "World";
// 模板字面量(支持多行和变量插值,用 ` ` 包裹)
let name = "Alice";
let multiLine = `Hello ${name},
This is a multi-line string.`;
console.log(multiLine);
// 输出:
// Hello Alice,
// This is a multi-line string.6.3 布尔字面量#
仅两个值:true(真)和 false(假)。
let isDone = false;
let hasPermission = true;6.4 null 和 undefined#
null:表示“空值”(主动赋值)。undefined:表示“未定义”(变量声明未赋值时的默认值)。
let emptyValue = null;
let unassignedVar; // undefined6.5 对象字面量#
用 {} 表示,包含键值对(属性)。
let user = {
name: "Bob",
age: 30,
isStudent: false
};6.6 数组字面量#
用 [] 表示,包含有序元素列表。
let fruits = ["apple", "banana", "cherry"];6.7 符号字面量(Symbol)#
用 Symbol() 创建,是唯一且不可变的值,用于对象属性的唯一键。
let uniqueKey = Symbol("id");
let obj = { [uniqueKey]: "value" };最佳实践:#
- 字符串统一引号:项目中统一使用单引号或双引号(如 ESLint 规则
quotes)。 - 模板字面量优先:多行字符串或需要变量插值时,优先使用模板字面量(
`)。 - 避免八进制陷阱:非严格模式下,以
0开头的数字可能被解析为八进制(如010是 8),建议用0o前缀显式表示八进制。
7. 运算符#
运算符用于对值进行操作,JS 支持多种运算符,按功能可分为:
常见运算符分类:#
- 算术运算符:
+(加)、-(减)、*(乘)、/(除)、%(取余)、**(幂)、++(自增)、--(自减)。 - 赋值运算符:
=、+=、-=、*=等。 - 比较运算符:
==(相等)、===(严格相等)、!=(不等)、!==(严格不等)、>、<、>=、<=。 - 逻辑运算符:
&&(与)、||(或)、!(非)。 - 位运算符:
&(与)、|(或)、^(异或)、~(非)、<<(左移)、>>(右移)、>>>(无符号右移)。 - 其他:
typeof(类型判断)、instanceof(实例判断)、in(属性判断)等。
示例:运算符使用#
// 算术运算符
let sum = 10 + 5; // 15
let power = 2 **3; // 8(2的3次方)
// 赋值运算符
let x = 10;
x += 5; // 等价于 x = x + 5 → x=15
// 严格相等(推荐,避免类型转换)
console.log(5 === "5"); // false(类型不同)
console.log(5 == "5"); // true(自动类型转换)
// 逻辑运算符(短路特性)
let result = true && "Hello"; // "Hello"(&& 取第一个假值,无假值则取最后一个值)
let result2 = false || "World"; // "World"(|| 取第一个真值,无真值则取最后一个值)最佳实践:#
- 优先使用严格相等(===):
==会触发隐式类型转换,可能导致意外结果(如"" == 0为true)。 - 避免连续赋值:如
a = b = c = 0,可读性差,建议拆分。 - 明确括号优先级:复杂表达式用括号明确运算顺序,避免依赖运算符优先级(如
a + b * c不如a + (b * c)清晰)。
8. 自动分号插入(ASI)#
JavaScript 允许省略语句末尾的分号(;),引擎会自动插入分号(Automatic Semicolon Insertion,ASI)。但 ASI 有规则限制,滥用可能导致逻辑错误。
ASI 触发场景:#
1.** 行终止符后 :若一行代码结束,且下一行开始的代码无法与当前行合并解析,则插入分号。
2. 代码块结束(})前**:如函数、循环、条件语句的 } 前。
3.** 文件结束时**:文件末尾自动插入分号。
ASI 陷阱示例:#
// 陷阱 1:return 后换行
function getValue() {
return // ASI 会在这里插入分号,导致返回 undefined
{ name: "Alice" };
}
console.log(getValue()); // undefined(而非 { name: "Alice" })
// 陷阱 2:数组/对象字面量换行
let arr = [1, 2, 3]
[4, 5].forEach(x => console.log(x)); // 报错:Cannot read property 'forEach' of undefined
// 原因:引擎将 [4,5] 解析为 arr[4,5](属性访问),而非新数组
// 陷阱 3:自增/自减运算符
let a = 1
++a
console.log(a); // 2(正常,但不推荐省略分号)最佳实践:#
-** 显式添加分号 **:避免依赖 ASI,尤其在以下场景必须加分号:
- 一行多个语句(如
let a=1; let b=2)。 return、break、continue后换行。- 以
[、(、+、-、/开头的行(如[1,2].forEach(...)前若有未加分号的语句)。
9. 总结与最佳实践#
JavaScript 词法结构是代码的“语法基石”,掌握以下核心原则可显著提升代码质量:
1.** 字符与编码 :优先使用 ASCII 字符,避免非标准符号。
2. 大小写敏感 :严格区分大小写,遵循命名规范(camelCase、PascalCase 等)。
3. 空白符 :统一缩进(2/4 空格),合理换行提升可读性。
4. 注释 :解释“为什么”,避免过时或冗余注释。
5. 标识符 :见名知意,不使用保留字,遵循命名约定。
6. 字面量**:统一字符串引号,优先用模板字面量处理多行文本。
7.** 运算符**:优先使用 ===,复杂表达式加括号明确优先级。
8.** ASI**:显式添加分号,避免依赖自动插入。
10. 参考资料#
- ECMAScript 规范(Lexical Grammar)
- MDN Web Docs:JavaScript 词法结构
- Google JavaScript 风格指南
- Airbnb JavaScript 风格指南
通过深入理解词法结构,我们能写出更规范、更易维护的 JavaScript 代码,为后续学习复杂语法和框架打下坚实基础。