注意换行的位置
了解分号和换行符在 JavaScript 中的作用。
引言
一些动态类型编程语言对分号不敏感,将其视为可选语法。但 JavaScript 并非如此。分号并非可选。在某些位置,分号至关重要;而在其他位置,它更多是一种风格选择。然而,如果你在需要分号的地方遗漏了它,JavaScript 不会报错。这是因为 JavaScript 遵循一种理念:与其抱怨,不如默默“报复”。
📝注意:仅仅简单地添加一个
;并不够。我们必须真正理解 JavaScript 的
自动分号插入(ASI) 规则。
JavaScript 的自动分号插入(ASI)规则
ASI 规则的两个核心要点如下,并附有示例说明:
第一条规则
一个有效的程序以分号结尾。如果某个脚本没有以分号结束,JavaScript 会自动插入一个分号。由于代码是从左到右逐个解析的,当遇到一个意外的标记,且该标记与前一个标记之间存在换行符时,JavaScript 会在该标记之前自动插入一个分号。
示例
例如,考虑以下代码片段:
1// 有错误的代码 2const unexpected = function() { 3 let first 4 second = 1; 5 6 console.log(first); 7 console.log(second); 8} 9 10unexpected(); 11console.log(second);
解释
- 我们使用
let和const而不是var——这是这段代码的优点。 - 然而,
first之后出现的second标记是不符合预期的,尽管两者之间有换行。因此,JavaScript 在second变量前悄悄插入了一个分号。这导致first的值为undefined,而second变成了全局变量——后果严重。 - 上述代码块的输出结果清楚地展示了这一点。
第二条规则
如果候选标记是 break、continue、return、throw 或 yield,并且该标记与下一个标记之间存在换行符,JavaScript 会自动在候选标记后插入一个分号。
示例
例如,以下代码中的第二个 return(第9行)写法不正确:
1// 有错误的代码 2const compute = function(number) { 3 if(number > 5) { 4 return number 5 + 2; // <label id="code.plus2" /> 6 } 7 8 if(number > 2) { 9 return 10 number * 2; 11 } 12}; 13 14console.log(compute(6)); 15console.log(compute(3));
解释
-
由于第二个
return后面紧跟着换行符,JavaScript 会在return后自动插入一个分号。因此,函数返回的是空值,即undefined,这可以从代码块的输出中看出。 -
在第一个
return中,虽然该行没有分号,但由于+可以合法地紧跟在number之后,所以不会在此处插入分号。不过,如果将第5行的+ 2改为2,JavaScript 就会在2前插入一个分号,导致结果为6,而不是因为发现不可达代码而报错。
建议
以下是一些有助于做出最佳决策的建议:
- 如果某行代码较短,应以清晰可见的分号结尾。按惯例,我们不在结束代码块的
}之后添加分号。 - 如果某行代码较长,应将其拆分为多行,但要确保拆分方式不会导致 JavaScript 因自动插入分号而偏离你的本意。
结语
从上述示例可以看出,问题并不在于分号是否可选,而在于我们如何断行。这种陷阱很容易陷入,但通过使用 lint 工具可以有效避免此类错误。