JavaScriptのコードを読んでいると、map や filter の中に line => line.trim() のような書き方がよく出てきます。これは「アロー関数」と呼ばれる、関数の短い書き方です。
C言語を長く書いてきた私には、関数をその場で作って引数に渡す書き方そのものが、最初はなじみのないものでした。C言語でいえば、qsort に比較関数のポインタを渡すのに近く、その関数を別の場所で定義せず、その場で書いてしまうイメージです。
この記事では、function を使った書き方から順に短くしてアロー関数の形を理解し、function との違いも確かめます。
アロー関数とは
アロー関数は、ES2015(ES6)で追加された関数の書き方です。=> が矢印(アロー)に見えるので、こう呼ばれます。function より短く書けることに加えて、関数の中の this の扱いが違うという特徴があります(後で説明します)。
そこで、同じ「数を2倍にする」関数を、いろいろな書き方で並べてみます。
// ① function で宣言する(関数宣言)
function double1(n) {
return n * 2;
}
// ② 名前のない関数を変数に入れる(関数式)
const double2 = function (n) {
return n * 2;
};
// ③ アロー関数
const double3 = (n) => {
return n * 2;
};
// ④ アロー関数で省けるものを省いた形
const double4 = n => n * 2;
console.log(double1(5), double2(5), double3(5), double4(5)); // 10 10 10 10どれも同じ結果になります。②の function を消して => を置くと③になり、③からカッコや return を省くと④になります。
map の中で書き換えてみる
アロー関数がいちばんよく使われるのは、map や filter のように、関数を引数として渡す場面です。ここでは、配列の文字列から前後の空白を取り除く処理を、順に短くしていきます。
第1段階:function で書く
const lines = [' りんご ', 'みかん ', ' ぶどう'];
const trimmed = lines.map(function (line) {
return line.trim();
});
console.log(trimmed); // ['りんご', 'みかん', 'ぶどう']map は、配列の要素を1つずつ line に入れて関数を呼び、戻り値を集めた新しい配列を作ります。trim() は、文字列の前後の空白を取り除くメソッドです。
第2段階:function を => に置き換える
const trimmed = lines.map((line) => {
return line.trim();
});function という言葉がなくなり、引数の (line) の後ろに => が入りました。function line => のように両方を書くのではなく、function の代わりに => を使う、と考えると分かりやすいです。
第3段階:引数のカッコを省く
const trimmed = lines.map(line => {
return line.trim();
});引数が1つだけのときは、引数を囲む () を省けます。
第4段階:{} と return を省く
const trimmed = lines.map(line => line.trim());関数の中身が「式を1つ返すだけ」のときは、{} と return も省けます。式の値がそのまま戻り値になります。実際のコードでよく見るのは、この形です。
同じように4段階で短くしていく流れを、filter を例に「filterメソッドの書き方」でも紹介しています。
省略のルールと注意点
引数の数でカッコの要る・要らないが変わる
const hello = () => 'Hello'; // 引数が0個:() は省けない
const square = n => n * n; // 引数が1個:() を省ける
const add = (a, b) => a + b; // 引数が2個以上:() は省けない
const greet = (name = 'ゲスト') => `こんにちは、${name}さん`; // デフォルト値を使うときも () が必要引数が1つでも () を付ける書き方は正しく、コードを自動で整える Prettier も、初期設定では (n) => ... のようにカッコを付けます。バッククォートを使った文字列は「文字列の ‘ と ” と ` の違い」で紹介しています。
オブジェクトを返すときは () で囲む
{} と return を省いた形でオブジェクトを返すときは、注意が必要です。{ が「関数の中身の始まり」と受け取られてしまうので、オブジェクトを () で囲みます。
const names = ['りんご', 'みかん'];
// 間違い:{ name: n } が関数の中身と受け取られ、undefined が返る
const ng = names.map(n => { name: n });
console.log(ng); // [undefined, undefined]
// 正しい:() で囲む
const ok = names.map(n => ({ name: n }));
console.log(ok); // [{ name: 'りんご' }, { name: 'みかん' }]function とアロー関数の違い
アロー関数は function を短くしただけのものではなく、動きが違うところがあります。
| 項目 | function | アロー関数 |
|---|---|---|
| 中の this | 呼び出し方で決まる | 外側の this をそのまま使う |
| new での呼び出し | できる | できない(TypeError) |
| arguments | 使える | 使えない(代わりに …args を使う) |
| 定義より前での呼び出し | 関数宣言ならできる | const に入れた場合はできない |
this の違い
いちばん大きな違いが this です。アロー関数は自分の this を持たず、外側の this をそのまま使います。そのため、メソッドの中でタイマーなどの関数を渡すときは便利ですが、メソッドそのものをアロー関数で書くとうまく動きません。
const timer = {
seconds: 0,
// 動く:メソッドの中のアロー関数は、start の this(timer)をそのまま使う
start() {
setInterval(() => {
this.seconds++;
console.log(this.seconds);
}, 1000);
},
// 動かない:メソッド自体をアロー関数にすると、this が timer を指さない
reset: () => {
this.seconds = 0; // timer.seconds は 0 に戻らない
},
};start の中の setInterval に function を渡すと、その中の this は timer を指さず、秒数が増えません。逆に、reset のようにオブジェクトのメソッドをアロー関数で書くと、this がオブジェクトを指さないので、メソッドはふつうの書き方(reset() { ... })にします。
クラスのメソッドの中で filter を使う例は、「filterメソッドの書き方」の「中で this を使うときはアロー関数にする」でも紹介しています。
定義より前で呼べるか
function で宣言した関数は、ファイルの上のほうからでも呼べます。const に入れたアロー関数は、その行より前では呼べません。
sayHello(); // OK:関数宣言は先に呼べる
function sayHello() {
console.log('Hello');
}
sayBye(); // ReferenceError:const の行より前では呼べない
const sayBye = () => {
console.log('Bye');
};どちらを使えばいい?
- map、filter、forEach、setTimeout などに渡す短い関数 → アロー関数が向いている
- オブジェクトやクラスのメソッド →
reset() { ... }のようなメソッドの書き方 - new で使う関数や、中で this を切り替えたい関数 →
function - ファイルのどこからでも呼ぶ普通の関数 → 関数宣言でも、const とアロー関数でもよい(プロジェクトの書き方に合わせる)
まとめ
- アロー関数は、
functionの代わりに=>を使う関数の書き方(ES2015で追加) - 引数が1つなら
()を、中身が式を返すだけなら{}とreturnを省ける - オブジェクトを返すときは
({ ... })のようにカッコで囲む thisは外側のものを使う。メソッドの中で渡す関数には便利だが、メソッドそのものには使わない
この記事のコードは、ブラウザのコンソールやCodePenに貼ればすぐに試せます。アロー関数は、画面の要素にクリックの処理を付けるときにもよく使います。要素の取得方法は「querySelectorで使えるCSSセレクターの書き方」で紹介しています。



コメント