基礎

JavaScriptのアロー関数入門|従来の関数との違いとthisの扱い

アロー関数(Arrow Function)は、ES6で導入された関数の短縮記法です。=>(矢印)を使って関数を定義するため、従来の function キーワードよりも簡潔にコードを書けます。コールバック関数や配列メソッドとの組み合わせで特に威力を発揮します。

ただし、アロー関数は単なる省略記法ではなく、this の扱いが根本的に異なるという重要な違いがあります。この記事では、基本構文から this の違い、使い分けのポイントまで解説します。

基本的な使い方

アロー関数は (引数) => { 処理 } の形式で記述します。引数が1つの場合は括弧を省略でき、処理が1つの式のみの場合は波括弧と return を省略できます。

JavaScript
// 従来の関数
const add1 = function(a, b) {
  return a + b;
};

// アロー関数(基本形)
const add2 = (a, b) => {
  return a + b;
};

// アロー関数(省略形:式が1つなら {} と return を省略可能)
const add3 = (a, b) => a + b;

// 引数が1つなら () も省略可能
const double = x => x * 2;

// 引数がない場合は () が必須
const greet = () => 'こんにちは!';

console.log(add1(3, 5));
console.log(add2(3, 5));
console.log(add3(3, 5));
console.log(double(7));
console.log(greet());
実行結果
8
8
8
14
こんにちは!

省略記法は短く書ける反面、読みにくくなる場合もあります。チームで開発する際はコーディング規約で統一するのが一般的です。引数が1つでも括弧を付ける((x) => x * 2)スタイルも多く採用されています。

配列メソッドとの組み合わせ

アロー関数が最も活躍するのは、mapfilterreduce などの配列メソッドのコールバック関数としての使用です。

JavaScript
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// map: 各要素を変換
const squared = numbers.map(n => n * n);
console.log('二乗:', squared);

// filter: 条件に合う要素を抽出
const evens = numbers.filter(n => n % 2 === 0);
console.log('偶数:', evens);

// メソッドチェーン
const result = numbers
  .filter(n => n % 2 !== 0)   // 奇数のみ
  .map(n => n * 3)             // 3倍にする
  .filter(n => n > 10);        // 10より大きいもの
console.log('奇数を3倍して10超:', result);

// sort(比較関数)
const users = [
  { name: '田中', age: 30 },
  { name: '鈴木', age: 25 },
  { name: '佐藤', age: 35 }
];
const sorted = [...users].sort((a, b) => a.age - b.age);
sorted.forEach(u => console.log(u.name + ': ' + u.age + '歳'));
実行結果
二乗: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
偶数: [2, 4, 6, 8, 10]
奇数を3倍して10超: [15, 21, 27]
鈴木: 25歳
田中: 30歳
佐藤: 35歳

従来の function を使うと冗長になるコールバックが、アロー関数では1行で済みます。メソッドチェーンと組み合わせることで、データの変換パイプラインを宣言的に記述できます。

thisの違い

アロー関数と従来の関数の最も重要な違いは this の扱いです。アロー関数は自身の this を持たず、外側のスコープの this をそのまま引き継ぎます。

JavaScript
const timer = {
  seconds: 0,

  // 従来の関数:thisがtimerオブジェクトを指さない
  startWrong() {
    setInterval(function() {
      this.seconds++;  // thisはwindow(またはundefined)
      console.log('Wrong:', this.seconds);  // NaN
    }, 1000);
  },

  // アロー関数:thisが外側(timer)を引き継ぐ
  startCorrect() {
    setInterval(() => {
      this.seconds++;  // thisはtimerオブジェクト
      console.log('Correct:', this.seconds);
    }, 1000);
  }
};

// クラスでの使用例
class Counter {
  constructor() {
    this.count = 0;
  }

  // メソッドとして定義
  increment() {
    this.count++;
    return this;
  }

  // イベントハンドラにはアロー関数が便利
  setupButton(button) {
    button.addEventListener('click', () => {
      this.count++;  // thisがCounterインスタンスを指す
      console.log('クリック数:', this.count);
    });
  }
}

従来の関数では、setIntervaladdEventListener のコールバック内で this が変わってしまうため、const self = this.bind(this) で対処する必要がありました。アロー関数を使えば、この問題が自然に解決されます。

オブジェクトリテラルを返す場合

アロー関数の省略記法でオブジェクトを返す場合、波括弧がブロックと解釈されるため、括弧で囲む必要があります。例: const getUser = () => ({ name: '田中', age: 30 }) のように () で囲みます。

アロー関数を使うべきでない場面

オブジェクトのメソッド定義にアロー関数を使うと、this がオブジェクト自身ではなく外側のスコープを参照してしまいます。メソッド定義には従来の関数(省略記法 method() { })を使いましょう。また、arguments オブジェクトやコンストラクタ(new)はアロー関数では使えません。

まとめ

  • アロー関数は (引数) => 式 の形式で簡潔に関数を定義できる
  • 引数が1つなら括弧を省略、式が1つなら波括弧と return を省略可能
  • mapfiltersort などのコールバック関数との相性が良い
  • アロー関数は自身の this を持たず、外側のスコープの this を引き継ぐ
  • オブジェクトのメソッド定義やコンストラクタにはアロー関数を使わない