You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
30-Days-Of-JavaScript/js_notes/00-concepts/semicolons-and-asi.md

3.0 KiB

通用概念 · 分号 ;:什么时候【必须】写

JS/TS 每句结尾的 ; 绝大多数可省(引擎会自动补),但有几种情况不写就是坑。 本篇只记"必须写、不写就出 bug"的场景。相关:../09-loops.js(无分号风格)。

背景:ASI —— 引擎会自动补分号

JS 有个机制叫 ASI(Automatic Semicolon Insertion,自动分号插入): 你不写 ;,引擎在换行处通常会替你补上。所以这两种写法行为完全一样:

const a = 1;   // 写了
const a = 1    // 没写,ASI 自动补 —— 等价

本仓库 js_notes/ 统一用无分号风格(Prettier 默认),保持一致即可,别混着来。 但无分号的前提是:知道下面这几个 ASI 会猜错的地方,主动兜底。

⚠️ 坑 1:下一行以 ([ 开头 → 必须在【行首】补 ;

ASI 看到下一行还能和上一行"连成一句",就不补分号,于是两行被黏成一句:

// 💥 出错:ASI 不补,被理解成 5[1,2,3]... 或 b(...)
const x = 5
[1, 2, 3].forEach((n) => console.log(n))   // TypeError: Cannot read properties...

const b = foo
(function () {})()                          // foo(function(){})() —— 把 foo 当函数调用

正解:在以 ( / [ 开头的那行,行首加 ;(不是上一行结尾):

const x = 5
;[1, 2, 3].forEach((n) => console.log(n))  // ✅ 行首 ; 把两句切开

口诀:一行别以 ([ 开头;非要这么写,行首先放一个 ; (常见于:上一行是赋值/表达式,下一行想直接 [...].map() 或 (...) 立即执行。)

⚠️ 坑 2:return / throw 等后面【不能】换行

这几个关键字后面一旦换行,ASI 会强制在关键字后补 ;,把真正想返回的东西丢掉:

// 💥 等于 return;  换行后的对象被当成"死代码"丢弃 → 函数返回 undefined
function make() {
  return
    { name: 'Tom' }
}
make() // undefined,不是那个对象!

正解:要返回的东西和 return 写在同一行(对象太长就用括号包起来接着写):

function make() {
  return { name: 'Tom' }   // ✅ 同一行
}

同样受影响的:return / throw / break / continue / yield —— 后面别换行

⚠️ 坑 3(顺带):同一行写两句,中间【必须】有 ;

分号真正的本职工作是"分隔语句"。想把两句挤在一行,中间必须;:

let a = 1 let b = 2      // 💥 语法错误
let a = 1; let b = 2     // ✅ 一行两句,靠 ; 分隔

一句话

平时跟着仓库的无分号风格写就行,ASI 帮你兜底。只死记两条保命规则:

  1. 行首是 ([ → 这一行行首;;
  2. return/throw/break/continue 后面不换行(要返回的写同一行)。

装了 Prettier 的话,保存时会自动帮你处理坑 1 的行首 ;,更省心。 TS 规则完全一样(TS 是 JS 超集),只是 TS 项目社区更偏爱每句都写 ; —— 那是团队约定,不是语法强制。