arrow function の引数は括弧で囲っておいた方が良さそうな件

  • 40
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

ES6 クイズの答え

ES6 クイズ は、俺自身が「いずれ引っかかりそうだな」と思ったもの。
「そう見えるのは俺だけかも。。」と思って何人かにクイズとして出してみたら、意外と引っかかったので俺だけじゃなさそうと思って書いた。

クイズ1

var a = 1;
if (a => 2) {
 console.log('bigger');
} else {
 console.log('smaller')
};

// bigger

a => 2 は比較演算ではなく、 arrow function なので常に true になる。
念のため言うと、本来比較演算の greater than は a >= 2

クイズ2

var a = 1, b = 2, c = 3, d = 4;
var f = a => b ? c: d;

// f = ?

1 と全く同じで、 f は arrow function になる。
(ab の比較なら a >= b)

わかりやすく書くとこう。

var f = (a) => { b ? c: d; }

つまり、 f を実行すると、 btruthy なので c が返る。

f(); // 3

ちなみに AST レベルでは 和田さんが調べてた のでそちらを参照。

本当の問題

この問題、単なる引っ掛けで済めば良いけど、
実際にだれかがこのコードをしれっと入れてしまったときに、気づくのって簡単だろうか。
(たとえ、このエントリを読んで、問題を知っていたとしても。)

特に初心者は、 <= の反対は => だろと思うのは無理も無いと思う。
というかそっちの方が直感的な気もするし。

本当の問題は、「今まで => はエラーだった」ということだ。
構文的に間違っていることを処理系が教えてくれたから、俺らは自然とそれを避けてこれた。

でも、 arrow function が有効な環境では、もうこれは Valid なものとして解釈されてしまう。
自分でそれに気づく仕組みを持っておきたいと思うのが、自然なアプローチのように思う。

対策

個人的には、以下のスタイルを強制するのが一番楽だと思う。
(もちろん、テストは書こう。でもその話はしてない。)

arrow function の引数は必ず `()` で囲む

そして、それを強制するための eslint plugin を書いた。

https://github.com/Jxck/eslint-plugin-arrow-function

[追記] @teppeis さんの PR で、 Condition が期待される部分のみ検出するルールを追加しました。 no-condition

これを入れれば、以下のようなコードは全て怒られる。

a => {}
a => a
a => {\n}
a.then(foo => {});
a.then(foo => a);
a(foo => { if (true) {}; });

こう直すと通る。

() => {}
(a) => {}
(a) => a
(a) => {\n}
a.then((foo) => {});
a.then((foo) => { if (true) {}; });

このルールを導入していると、クイズのコードはこう書かないと動かなくなり、
もし比較演算を意図していたなら、おかしいことに気づけると思う。

if ((a) => 2) {
  // snip
}
var f = (a) => b ? c: d;

中括弧や return まで強制すればもっと良いかもしれないけど、それは arrow function の旨味まで消えている気がするので、
スタイルで強制するのはこのくらいがちょうどいいと思う。今のところ違和感は感じてない。

なお、「今まで動かなかったコードが動くようになる」ということがもたらす問題に、これからもっと直面するだろうなと思う。