【JS】JavaScriptからセミコロンを外す時に気をつけるポイント
こんにちは!気温が体温を超えるとやばみありますよね!Mizutani(@sirycity)です。名古屋は今37度。
今日は宗教戦争意見が割れがちなJavaScriptのセミコロンについて。**今までセミコロンを付けていた人がセミコロンを外す時にはどういう所に注意すればいいの?**って話をします。
セミコロンっているの?いらないの?
どっちでもいいです。完全に好みです。タブvsスペースみたいなもん。
…なんだけど、元々セミコロンありで書いていた人がいきなり全部セミコロン取るとハマるポイントがあるんですね。なので**こう書いてたやつをこう書こう!**ってのを紹介していきます。
気をつけるポイント
基本的に気をつける点は3箇所。いずれもセミコロンを取ると同時に行頭に何かを付ける必要があります。
即時関数
即時関数、セミコロンありで書いてる人は元々こうやって書いてたりしない?
;(() => {
console.log(42)
})()
セミコロンを外すならこんな風に書こう!
;(() => {
console.log(42)
})()
!(() => {
console.log(42)
})()
~(() => {
console.log(42)
})()
末尾のセミコロンを外すだけじゃなくて即時関数の先頭にセミコロン、否定演算子、チルダあたりのどれかを書きましょう。どれでもおk。セミコロンのときが多いかな?僕は視覚的に綺麗なのでチルダ派です。
ただし、同時に本当に即時関数が必要な場面かを考えるようにすると良いかと思います。例えばvarのスコープを切る目的で即時関数を使っている場合はvarをconstに変える事で解決可能かもしれません。
スプレッド構文を用いた配列初期化
配列初期化にスプレッド構文使う派の人は注意。fillとかArray.fromなら大丈夫だけどね。
;[...Array(42)].map(v => console.log(42))
// 注意!
Array(42)
.fill()
.map(v => console.log(42))
// 大丈夫
Array.from(Array(42)).map(v => console.log(42))
// 大丈夫
これもセミコロン取る段階で頭にセミコロン、否定演算子、チルダあたりを付けてあげましょう。
;[...Array(42)].map(v => console.log(42))
![...Array(42)].map(v => console.log(42))
~[...Array(42)].map(v => console.log(42))
ただ、これも使われるケースは結構稀だったりします。こんな風に↓たいてい代入しちゃうからね。そんでこのパターンなら頭に何もつけなくてもおk。
const foo = [...Array(42)].map(v => v)
上のconsole.log(42)
みたいな戻り値がvoidになる配列初期化の時だけ頭に付ける必要があります。
分割代入で再代入
再代入をする時に分割代入を使うようなパターンは注意。こういうやつね。
let n = {}
;[n.one, n.two] = [1, 2]
こういう時は分割代入の前にセミコロン付けましょう。この時は否定演算子とかチルダはダメ。
let n = {}
;[n.one, n.two] = [1, 2]
とはいえ、このパターンも回避可能というか、letを使わなければ再代入は意識位しなくて良いです。例えばこんな風に。
const n = {
one: 1,
two: 2,
}
ただこのパターンのletはtry-catchでよく使われるからconstに置換できなかったりするんですね!こんな感じで。
let n = {}
try {
;[n.one, n.two] = [1, 2]
} catch {
;[n.one, n.two] = [null, null]
}
そういう時はawait-catch使いましょう。こう。
const success = () => ({
one: 1,
two: 2,
})
const failure = () => ({
one: null,
two: null,
})
const n = await success().catch(failure)
なぜ先頭に記号を付けるのか
なんでセミコロンを取ると同時に頭にセミコロンやら何やらつけなきゃならんのでしょう?
例えばこんな時、
const one = 1
;(() => {
console.log(42)
})()
普通にセミコロン取るとこうなるんですが、
const one = 1(() => {
console.log(42)
})()
そうなると上の1と下の即時関数の最初の()が合体して1が関数みたいに扱われてしまうんです。こんな風に。
const one = 1(() => {
console.log(42)
})()
JavaScriptは改行しても文法的に妥当であれば続けて解釈されるので(厳密にはもうちょい難しいんだけど)、こういう風になるんですね!なので、即時関数の頭に色々付けることで関数として解釈できなくするんです。これが行頭にセミコロンやら否定やらチルダやら付ける意味です。その記号が必要なんじゃなくて、文法の解釈を変えてるみたいな感じ。
なので、上で挙げた3つの例(即時関数、スプレッドの配列初期化、分割代入で再代入)がダメというよりは (や[で始まる所の先頭に記号を付けるって考えた方がより正しいかもしれないですね。
めんどくさくない?
**そんないちいち括弧の位置とか気にしてられんわやっぱセミコロン付けよ!**ってなりません?
…それはもう全く仰る通りで、冒頭にも書いた通りセミコロン付けるか付けないかはほぼ趣味の領域なので自由にやって良いと思います。
ただ、あえて言うならば…セミコロンなしは慣れます。僕はセミコロンを付けなくなって3年ほどですが、即時関数は~(() => {})()
←もうこういうものだと思っています。わざわざ意識してチルダ付けてるわけじゃないです。配列初期化も~[... Array(n)]
って記号付きで自然に出てきます。
最後に
好きな方使お。