【JS】JavaScriptのifはどうしたら見やすくなるのか
こんにちは!もし人生をやり直せるなら1995年に生まれたかったMizutani(@sirycity)です。JavaScriptと同い年。
今日はJavaScriptのifがどうやったら見やすくなるかについてです。ifはもうプログラミングの基本中の基本ですが、だからこそクールに書きたいですよね(?)
JavaScriptのifについて
こんなおもっくそエンジニア向けのブログでifを解説する意味なんてないと思うけど、一応こんな感じ。
const n = 42
let ans
if (n <= 40) {
ans = '40よりちいさいか40だよ'
} else {
ans = '40よりおおきいよ'
}
console.log(ans)
JavaScriptのifのダメなところ
式じゃなくて文
これが一番やばい。JavaScriptのifは式じゃなくて文です。なのでこういう書き方はできない。※このコードは動きません
const n = 42
const ans =
if (n <= 40) '40よりちいさいよ'
else '40よりおおきいよ'
console.log(ans)
ifを式として使える言語は多いです。すげー有名どころだとrubyとかpythonとか。でもJSは無理。その結果何が起こるかと言うと…
丸括弧と波括弧が必須
そう、こうなる。長くなる。まあ括弧を付けるとスコープが視覚的に分かりやすくなるので別に悪いことではないんだけどね。でもあんまり綺麗じゃないね。
else ifが長い
あとついでにelse ifが長い。rubyはelsif、pythonだとelif。まあたった3文字の違いだけど。
それにelse ifは 「else if」でひとまとまりなのに間にスペースがあるせいで可読性が悪いです。流し読みする時に判別し辛い…
ifを見やすくする大作戦
というわけでそんな分かりにくいif、分かりやすくしてみましょう。今回はこちらの適当に作った例を使います。何の処理なんだこの関数
const main = color => pref => {
if (color === 'red') {
if (pref === '青森') {
fn('りんご')
}
fn('いちご')
fn('さくらんぼ')
} else if (color === 'yellow') {
fn('レモン')
fn('パイナップル')
} else {
fn('みかん')
}
}
elseをなくす
これは賛否両論あると思いますが(保険)、個人的にはelse ifとelseは全く使いません。else ifの文句はさっき言いましたが、elseはifを見ないと「何以外」なのかが分からないからってのも大きいです。例えば上の例のelseは赤と黄色以外だけど、もし上側が200行とかあったらめっちゃ判別し辛いです。まあTypeScriptなら多少ましになるけども。
というわけでelseをなくしてみました。こう。
const main = color => pref => {
if (color === 'red') {
if (pref === '青森') {
fn('りんご')
}
fn('いちご')
fn('さくらんぼ')
return
}
if (color === 'yellow') {
fn('レモン')
fn('パイナップル')
return
}
if (true) {
fn('みかん')
return
}
}
elseをなくす代わりにifのスコープの最後にreturnを置いてます。一応ちょっと見やすくはなったかな?
…でもreturn書くの忘れそうだし、elseに相当する部分がif(true)になっていてちょっと違和感あります。最後のみかんの所はfn(‘みかん’)だけで良いんだけど、そうすると一見この関数が条件分岐とは無関係な関数に空目してしまいそうです。どっちにしろ、elseを排除したくらいじゃあんま見やすさは変わらない気がします。
switchを使う
どうぞ。
const main = color => pref => {
switch (color) {
case 'red':
if (pref === '青森') {
fn('りんご')
}
fn('いちご')
fn('さくらんぼ')
break
case 'yellow':
fn('レモン')
fn('パイナップル')
break
default:
fn('みかん')
break
}
}
うん、綺麗。
…やはり賛否両論あると思いますが(保険)、個人的にはswitchも殆ど使いません。switchはコロン・break・defaultと独自の演算子と構文がてんこ盛りな上にbreakは書き忘れに非常に気づきにくい。4重苦くらいあります。あと上の青森みたいに条件がネストすると綺麗さ半減。シンプルな条件ならswitch使えばだいぶ綺麗にはなりそうですね!
三項演算子
はいどうぞ。
const main = color => pref =>
color === 'red'
? fn('いちご') || fn('さくらんぼ') || (pref === '青森' && fn('りんご'))
: color === 'yellow'
? fn('レモン') || fn('パイナップル')
: fn('みかん')
ぶっちゃけ、この世の終わりって感じね。あまりにも可読性を犠牲にしすぎです。嫌われている三項演算子のネストに加えandとorまで総動員しています。僕は三項演算子読むのかなり得意なのでこのくらいはぶっちゃけ…って感じですが、これを複数人での開発時に書いたら120%リジェクトでしょう。やっぱり三項演算子はシンプルな条件に限るね。でも綺麗さはすごい。特に波括弧もreturnもない所。
ifを複数書く
どうぞ。
const main = color => pref => {
if (color === 'red' && pref === '青森') fn('りんご')
if (color === 'red') fn('いちご')
if (color === 'red') fn('さくらんぼ')
if (color === 'red') return
if (color === 'yellow') fn('レモン')
if (color === 'yellow') fn('パイナップル')
if (color === 'yellow') return
fn('みかん')
}
あれっ…これ以外とありかも。同じような式沢山かいててDRYの原則破ってるしタイプ量も多いけど、視覚的にはかなり見やすい!ちょっと変更に弱すぎるのが気になるけど…まあ、場合によっちゃあり?くらいですかね。
&&を複数書く
そろそろ飽きた?僕もです。
const main = color => pref => {
color === 'red' && pref === '青森' && fn('りんご')
color === 'red' && fn('いちご')
color === 'red' && fn('さくらんぼ')
color === 'yellow' && fn('レモン')
color === 'yellow' && fn('パイナップル')
color !== 'red' && color !== 'yellow' && fn('みかん')
}
これも以外とあり。見やすいね。最後がちょっと冗長かな?
結論
ifは色んな工夫でちょっと見やすくなる。んだけど見やすくするのは限界があるし、一番大事なのは分岐を極力少なくする設計だなーと思いました。結局そこかい!って話だけどね。
あと書いてて思ったけどJavaScriptの比較って実質的には厳密等価演算子a === b
とArray.includes[a].includes(b)
しかないし(今回inclduesは使ってないけど)、もうちょいバリエーション欲しいですね。pythonのisとかC#やJavaのEqualsとか。厳密等価演算子をずーっと見てたら頭が痛くなってしまったので今回はこのあたりにしようと思います。以上。