---
title: "アロー関数とは？functionとの違い・thisの挙動と使い分け【TypeScript・React・PHP】"
url: "https://www.issoh.co.jp/tech/details/3575/"
published: 2024-09-12
updated: 2026-11-02
categories: ["JavaScript"]
publisher: "株式会社一創"
---

# アロー関数とは？functionとの違い・thisの挙動と使い分け【TypeScript・React・PHP】

アロー関数は、ECMAScript 2015（ES6）で追加された `=>` を使う関数の書き方です。短く書けるだけではありません。`this` が呼び出し方ではなく定義した位置で決まり、`new` できず、`arguments` も持ちません。この差を知らずに `function` と入れ替えると、オブジェクトのメソッドが例外も出さずに壊れます。この記事では、Node.js v26.5.0・TypeScript 7.0.2・ESLint 10.14.0・React Compiler 1.0.0 で実際に動かした結果をもとに、違いと使い分けを整理します。PHPの `fn` と、名前の似た「アロー演算子」との違いも最後に扱います。

## まとめ：アロー関数とfunctionの使い分けの結論

実務の原則は1行で済みます。**コールバックはアロー関数、`this` で自分のオブジェクトを触るメソッドと `new` する関数は `function`（またはクラス構文）**です。`map`・`setTimeout`・Promiseの `then` に渡す処理は、外側の `this` をそのまま使えるアロー関数の方が安全です。

アロー関数にすると構文エラーになるのは、コンストラクタ（`new`）とジェネレータ（`yield`）です。それ以外は書けても意味が変わり、`this` と `arguments` が外側のものになります。オブジェクトリテラルのメソッドをアロー関数にすると、`this` が意図した対象を指さないまま動くので、構文エラーより見つかるのが遅れます。どちらでも書ける場面は、前方から呼びたい関数だけ `function` 宣言にし、残りはESLintの設定で固定すると、レビューで好みの議論をせずに済みます。Reactのコンポーネントはどちらでも挙動は同じで、TypeScriptの `.tsx` でジェネリックを取るときだけ `function` 宣言が有利です。

## アロー関数の書き方と省略ルール

基本形は `(引数) => 式` です。本体が式1つなら波括弧と `return` を省略でき、これを式本体と呼びます。引数の丸括弧を省略できるのは、単純な引数がちょうど1つのときだけです。

```
const double = (n) => n * 2;
const double2 = n => n * 2;            // 単純な引数1つなら括弧を省略できる
const greet = () => "hello";            // 引数なしは括弧が必須
const sum = (a, b) => a + b;            // 複数の引数も括弧が必須
const first = ([head]) => head;         // 分割代入・デフォルト値・残余引数も括弧が必須
const total = (a, b) => {               // 複数の文を書くなら波括弧と return
  const s = a + b;
  return s;
};
```

### 書き間違えやすい3つの形と実行結果

次の3つは、エラーにならずに値が変わるか、構文エラーで止まるかのどちらかです。コメントは、各例を1つずつ Node.js v26.5.0 で評価した結果です（まとめて実行すると最初の構文エラーで止まります）。

```
(() => { name: "x" })();          // undefined（波括弧が関数本体、name: はラベル扱い）
(() => ({ name: "x" }))();        // { name: "x" }（オブジェクトは丸括弧で囲む）

const f = (a)
  => a;                           // SyntaxError: Unexpected token '=>'

let cb;
cb = cb || () => {};              // SyntaxError: Malformed arrow function parameter list
cb = cb || (() => {});            // 丸括弧で囲めば動く
```

1つ目は最も気づきにくい形です。戻り値が `undefined` になるだけで、例外は出ません。2つ目は、引数の括弧と `=>` の間で改行した場合です。`=>` の後ろなら改行しても問題ありません。3つ目は、[MDNのアロー関数式のページ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow%5Ffunctions)が「アロー関数の優先順位」として挙げている例で、`||` の右辺に置くときは丸括弧が要ります。

### async・即時実行・カリー化の読み方

他人のコードで戸惑いやすい書き方を3つ並べます。

```
const load = async (url) => (await fetch(url)).json();   // async は引数の前に置く

(() => {
  // 即時実行：定義してすぐ呼ぶ。外にスコープを漏らさない
})();

const add = (a) => (b) => (c) => a + b + c;   // 関数を返す関数を返す
add(1)(2)(3);                                  // 6
```

`async` と引数の括弧の間で改行すると、`async` が通常の関数呼び出しとして解釈され、Node.js v26.5.0 では `SyntaxError: Malformed arrow function parameter list` になります。`a => b => c => ...` の形は、右から `function (a) { return function (b) { ... } }` と展開して読むと構造が分かります。引数を1つずつ受け取るこの書き方は、[関数型プログラミングとは？純粋関数・不変性・高階関数をTypeScriptの実例で解説](/tech/details/4841/)で高階関数として扱っています。

## thisの決まり方：functionは呼び出し方、アロー関数は定義位置

`function` で定義した関数の `this` は、定義した場所ではなく呼び出し方で決まります。`obj.method()` なら `obj`、単独で `fn()` なら `undefined`（strictモード）かグローバルオブジェクト、`call`・`apply` で渡せばその値です。アロー関数は自分の `this` を持たず、定義したスコープの `this` をそのまま参照します。`call`・`apply`・`bind` で別の値を渡しても無視されます。

### オブジェクトのアロー関数プロパティとthisの参照先

```
const counter = {
  count: 0,
  incArrow: () => { this.count++; },   // this はオブジェクトの外側
  incMethod() { this.count++; },       // this は counter
};

counter.incArrow();
console.log(counter.count);   // 0 のまま
```

`this` を使わない関数ならアロー関数のプロパティでも問題ありません。`this` で自分のオブジェクトを触る場合の壊れ方は、実行環境で分かれます。Node.js v26.5.0 の CommonJS では、トップレベルの `this` が `module.exports` を指すため、例外が出ないまま `count` が 0 で残ります。ES Modules ではトップレベルの `this` が `undefined` なので、同じコードが `TypeError: Cannot read properties of undefined (reading 'count')` で止まります。黙って壊れるCommonJSの方が発見は遅れます。

### コールバック・イベントリスナーのthis継承と使い分け

同じ性質が、コールバックでは利点になります。`function` を渡すと `this` が呼び出し元の都合で差し替わるためです。Node.js v26.5.0 で確かめると、`setInterval` に渡した `function` の `this` は `Timeout` オブジェクト、`EventTarget` の `addEventListener` に渡した `function` の `this` はイベントのターゲットでした。アロー関数ならどちらも外側の `this` のままです。

```
class Timer {
  constructor() { this.sec = 0; }
  start() {
    setInterval(() => { this.sec++; }, 1000);   // this は Timer インスタンス
  }
}

button.addEventListener("click", function () {
  this.classList.toggle("on");                 // this はリスナーを登録した button
});
```

ES5では `var self = this;` で退避するのが定番でしたが、アロー関数ならこの行が要りません。逆に、イベントリスナーの中で「リスナーを登録した要素」を `this` で取りたいときは `function` を使うか、アロー関数で `event.currentTarget` を参照します。`button` の中の子要素をクリックした場合、実際にクリックされた要素は `event.target` で、`this` とは一致しません。コールバックとPromiseの関係は[非同期処理とは？同期処理との違いから実装方式まで実装者目線で解説](/tech/details/13590/)で整理しています。

### クラスフィールドのアロー関数とメソッドの違い

```
class C {
  field = () => this;     // クラスフィールド
  method() { return this; }
}
const c1 = new C(), c2 = new C();
c1.field === c2.field;    // false（インスタンスごとに別の関数）
c1.method === c2.method;  // true（prototype で共有）

const { field, method } = c1;
field() === c1;           // true（取り出しても this が外れない）
method();                 // undefined（this が外れる）
```

クラスフィールドのアロー関数は、メソッドを取り出して渡しても `this` が外れません。そのかわりインスタンスを作るたびに関数が1つ増えます。取り出して渡しても `this` を保ちたいメソッドだけをクラスフィールドにし、インスタンスを大量に作るクラスでは、メモリ使用量を計測したうえで `bind` やメソッドと比べて選びます。

## アロー関数にできないこと：new・arguments・ジェネレータ・引数名の重複

`this` 以外の差を Node.js v26.5.0 で確かめた結果です。

| 項目                     | function                    | アロー関数         |
| ---------------------- | --------------------------- | ------------- |
| this                   | 呼び出し方で決まる                   | 外側を継承         |
| new                    | 可                           | TypeError     |
| prototype プロパティ        | あり                          | なし            |
| arguments              | 自分のもの                       | 外側の関数のもの      |
| yield（ジェネレータ）          | 可                           | SyntaxError   |
| 引数名の重複                 | 非strictかつ単純な引数リストなら可        | 常にSyntaxError |
| call・apply・bind の this | 反映される                       | 無視される         |
| super                  | メソッド構文のみ可（通常の function は不可） | 外側のメソッドを継承    |
| new.target             | 自前の束縛                       | 外側を継承         |

最も遭遇しやすいのは `new` で、`TypeError: Foo is not a constructor` で止まります。`arguments` は「無い」のではなく、書くと外側の `arguments` を探しにいきます。外側の関数の中なら、その関数の `arguments` を黙って参照します。ES Modules のトップレベルのように外側に束縛が無い場所では `ReferenceError: arguments is not defined` です（CommonJSでは、モジュールを包む関数の `arguments` が見えてしまいます）。可変長の引数は残余引数 `(...args) =>` で受けてください。引数名の重複は、`function (a, a)` が非strictモードでは通るのに対し（デフォルト値などを含む `function (a, a = 1)` は非strictでもSyntaxError）、`(a, a) => a` は `SyntaxError: Duplicate parameter name not allowed in this context` になります。

`super` と `new.target` は誤解が多い行です。アロー関数は自前の束縛を持たないだけで、外側のメソッドやコンストラクタのものを使えます。クラスのメソッド内で定義したアロー関数から `super.hello()` を呼ぶと動き、コンストラクタ内のアロー関数から `new.target` も取れました。`super` を使えるのはクラスやオブジェクトリテラルのメソッド構文の中だけなので、トップレベルや通常の `function` の中に置いたアロー関数で書くと `SyntaxError: 'super' keyword unexpected here` になります。

## functionとの使い分け：巻き上げとESLintでのルール化

制約に触れない場面、つまりどちらでも書ける場面の判断材料は、巻き上げの有無と、チームで揺れないルールの2つです。

### 関数宣言の巻き上げとconstのTDZ

```
hoisted();                       // 動く
function hoisted() {}

notHoisted();                    // ReferenceError: Cannot access 'notHoisted' before initialization
const notHoisted = () => {};
```

`function` 宣言は巻き上げられるので、定義より前の行から呼べます。ファイルの上に処理の流れを書き、下に部品を並べたいときや、相互再帰のように互いを前方参照するときは `function` 宣言が向きます。相互再帰は[再帰関数とは？自分を呼ぶ関数の仕組みとスタック・末尾再帰・実務判断を解説](/tech/details/15264/)で扱っています。

「アロー関数は無名なのでスタックトレースで追えない」という説明は今は当てはまりません。`const myArrow = () => {}` は変数名から名前が推論され、`myArrow.name` は `"myArrow"`、Node.js v26.5.0 のスタックトレースにも `at myArrow` と出ます。名前が出ないのは、`map` の引数などに直接書いたアロー関数だけです。

### ESLint 10で使い分けを固定する設定

```
// eslint.config.mjs
export default [
  {
    rules: {
      "func-style": ["error", "declaration", { allowArrowFunctions: true }],
      "prefer-arrow-callback": "error",
      "arrow-body-style": ["error", "as-needed"],
    },
  },
];
```

この設定で次の4行を ESLint 10.14.0 にかけると、3行に指摘が出ました。

```
const a = [1, 2].map(function (n) { return n * 2; });  // prefer-arrow-callback: Unexpected function expression.
const top = () => 1;                                  // 指摘なし（allowArrowFunctions で許可）
const f = function () {};                              // func-style: Expected a function declaration.
const b = (x) => { return x + 1; };                    // arrow-body-style: Unexpected block statement ...
```

3つのルールはいずれも非推奨ではありませんが、ESLint 10.14.0 のルール定義では3つとも `frozen: true` で、[ESLint公式のルールページ](https://eslint.org/docs/latest/rules/prefer-arrow-callback)にも Frozen と表示されています。新しいオプションを受け付けないという意味で、動作は維持されるので設定に残して構いません。`allowArrowFunctions: true` はトップレベルのアロー関数の代入も許すので、関数宣言に統一したいなら外します。

一方、`arrow-parens`・`arrow-spacing`・`no-confusing-arrow` は非推奨で、ルール定義の移行先は `@stylistic/eslint-plugin` の同名ルールです。古い記事の設定をそのまま貼っている場合は移してください。ルールで決めることとレビューで見ることの分け方は[コードレビューとは？目的・観点・進め方と実装現場の運用設計を解説](/tech/details/13384/)で書いています。チームの規約づくりから開発を任せたい場合は、[フルスクラッチ開発](/service/system/fullscratch/)でご相談いただけます。

## TypeScriptでのアロー関数：型注釈・thisパラメータ・.tsxのジェネリック

TypeScriptでは `=>` が、値としてのアロー関数と、関数の型の両方に出てきます。

```
const add: (a: number, b: number) => number = (a, b) => a + b;
//         ↑ 型（数値2つを受けて数値を返す）         ↑ 値（実際の関数）

type ClickHandler = (e: MouseEvent) => void;

function handler(this: HTMLElement) { return this.id; }   // this の型を宣言できる
const bad = (this: HTMLElement) => 1;                     // TS2730
```

関数の型を型エイリアスにしておくと、コールバックの引数に毎回注釈を書かずに済みます。`this` の型を宣言する [this パラメータ](https://www.typescriptlang.org/docs/handbook/2/functions.html)は `function` 専用で、アロー関数に書くと TypeScript 7.0.2 では `TS2730: An arrow function cannot have a 'this' parameter.` になります。アロー関数は `this` を外側から受け取るので、宣言する意味がないためです。

厄介なのは `.tsx` でのジェネリックです。`<T>` がJSXの開始タグと区別できず、TypeScript 7.0.2 では `TS17008: JSX element 'T' has no corresponding closing tag.` と `TS1382` が出ます（閉じタグを探す副作用で `TS1005` も出ます）。

```
const bad = <T>(x: T): T => x;                   // .tsx ではエラー
const ok1 = <T,>(x: T): T => x;                  // 末尾カンマを付ける
const ok2 = <T extends unknown>(x: T): T => x;   // 制約を付ける
function ok3<T>(x: T): T { return x; }           // function 宣言なら制約なし
```

下の3行はエラーなしで通ります。`<T,>` は意図が読み取りにくいので、ジェネリックなヘルパーは `function` 宣言で書くのが無難です。同じ関数を `.ts` に置けばこの制約はありません。TypeScriptの版ごとの差は[TypeScript 6.0とは｜5から6への移行手順とts5to6・7.0との違い【6.0.3対応】](/tech/details/11066/)にまとめています。

## Reactでのアロー関数：function宣言とどっちか、インライン関数とReact Compiler

**コンポーネントの定義はアロー関数でよく、ジェネリックを取るコンポーネントだけ `function` 宣言にします。**関数コンポーネントはどちらで書いても挙動もHooksの使い方も同じで、差が出るのは前の章の `.tsx` の制約だけです。

判断が分かれてきたのは、JSXの属性に直接書くインラインのアロー関数です。

```
const List = memo(function List({ onSelect }) { ... });

function Counter() {
  const [count, setCount] = useState(0);
  return <List onSelect={() => setCount(count + 1)} />;
}
```

コンパイラを使わない場合、この関数はレンダーのたびに作り直され、`memo` した `List` も毎回再レンダーされます。そのため `useCallback` で参照を固定するのが定石でした。ただしこの関数は `count` を閉じ込めているので、依存配列に `count` を入れれば `count` が変わるたびに参照も変わります。固定が効くのは、`count` が変わらない再レンダーのときです。

[React Compiler](https://react.dev/learn/react-compiler)を入れると前提が変わります。上のコードを babel-plugin-react-compiler 1.0.0 で変換すると、`Counter` の中身は次のようになりました（抜粋。\_jsxDEV の末尾引数は省略）。

```
const $ = _c(2);
let t0;
if ($[0] !== count) {
  t0 = _jsxDEV(List, { onSelect: () => setCount(count + 1) });
  $[0] = count;
  $[1] = t0;
} else {
  t0 = $[1];
}
```

インラインのアロー関数を含む要素ごと、`count` が変わらない限り前回の値が再利用されます。手で `useCallback` を書かなくても、参照が変わるのは `count` が変わったときだけです。React Compilerを導入済みなら、インラインのアロー関数を理由に書き方を変える必要はありません。未導入のプロジェクトでも、通常のDOM要素に渡すだけなら関数の作り直しは問題になりません。`useCallback` を検討するのは、[React公式のuseCallbackのページ](https://react.dev/reference/react/useCallback)が挙げるように、`memo` した子に渡すときや、Effectなど他のHookの依存配列に入る関数、カスタムHookから返す関数です。導入手順は[React Compilerとは？Vite・Next.js・Expoでの導入とRust版・ESLint・useMemoの扱い【2026年10月】](/tech/details/9415/)で解説しています。

## PHPのアロー関数fnとアロー演算子：JavaScriptとの違い

「アロー関数」で検索すると、PHPの公式マニュアルも上位に出ます。PHPのアロー関数は `fn` キーワードで書き、[PHPマニュアルのアロー関数のページ](https://www.php.net/manual/ja/functions.arrow.php)のとおり PHP 7.4 で追加されました。JavaScriptとの違いは、外側の変数の取り込み方と、本体に書ける量です。コメントは PHP 8.5.8 での実行結果で、最後の1行だけは別ファイルで実行した結果です（同じファイルに置くと全体が解析エラーになります）。

```
<?php
$y = 1;
$fn = fn($x) => $x + $y;     // use を書かなくても $y を取り込む
echo $fn(2);                 // 3
$y = 10;
echo $fn(2);                 // 3 のまま（定義した時点の値をコピー）

$inc = fn() => $y++;
$inc();
echo $y;                     // 10 のまま（外側の変数は書き換わらない）

echo implode(",", array_map(fn($v) => $v * 2, [1, 2, 3]));   // 2,4,6

$f = fn($x) => { return $x; };   // Parse error: syntax error, unexpected token "{"
```

JavaScriptのアロー関数は外側の変数を参照で共有するので、後から `$y` にあたる変数を書き換えると結果も変わります。PHPの `fn` は定義時の値をコピーするので変わりません。また、PHPの `fn` の本体は式1つだけで、波括弧のブロックは書けません。複数の文が要るときは従来の `function () use ($y) { ... }` を使います。`$this` はクラスのメソッド内なら自動で使え、この点はJavaScriptと同じ発想です。PHPの最新版の変更点は[PHP 8.5の変更点と新機能｜8.4との違い・非推奨・性能を実行結果で確認【8.5.12対応】](/tech/details/8179/)で確認できます。

もう1つ紛らわしいのが「アロー演算子」です。これはPHPの `$obj->prop` やC・C++の `ptr->member` のように、`->` でオブジェクトのメンバーを参照する記号の呼び名です。関数を作る構文ではなく、JavaScriptには `->` という演算子はありません。JavaScriptの `=>` もアロー関数の構文の一部で、単独の演算子ではありません。

## ラムダ式・無名関数との違い：Java・Python・C#との比較

アロー関数を「JavaScriptのラムダ式」と呼ぶ説明もありますが、仕様上の名前はアロー関数（[ECMAScript仕様の Arrow Function Definitions](https://tc39.es/ecma262/#sec-arrow-function-definitions)）です。名前を持たない関数を式として書く仕組みは各言語にあり、記号と書ける量が違います。

| 言語         | 記法                      | 本体    | 外側の変数     |
| ---------- | ----------------------- | ----- | --------- |
| JavaScript | `(a, b) => a + b`       | 式・複数文 | 参照で共有     |
| PHP        | `fn($a, $b) => $a + $b` | 式のみ   | 値をコピー     |
| Java       | `(a, b) -> a + b`       | 式・複数文 | 実質finalのみ |
| Python     | `lambda a, b: a + b`    | 式のみ   | 参照で共有     |
| C#         | `(a, b) => a + b`       | 式・複数文 | 参照で共有     |

Javaのラムダ式は関数型インターフェースの実装として扱われ、取り込めるローカル変数は再代入しない（実質final）ものに限られます。この制約は[キャプチャリングとは？Javaのラムダ式・匿名クラスと実質finalの制約](/tech/details/7145/)で、使いどころは[Javaラムダ式の使いどころ｜Stream APIで効く場面と避ける場面をJava 25で実測](/tech/details/2598/)で詳しく扱っています。

## よくある質問

### アロー関数とはどういう意味ですか？

ECMAScript 2015（ES6）で追加された、`=>` を使って関数を式として書く構文です。記号が矢印（arrow）に見えることが名前の由来です。`this`・`arguments`・`super`・`new.target` を自分では持たず、外側のものを使う点が `function` との本質的な違いです。

### JavaScriptの () と => は何を表しますか？

`()` が引数のリスト、`=>` が引数と本体の区切りです。`(a, b) => a + b` は「a と b を受け取り、a + b を返す関数」と読みます。`=>` の右に波括弧を書くと通常の関数本体になり、値を返すには `return` が要ります。

### アロー関数のメリットは何ですか？

コールバックの中で外側の `this` をそのまま使えることです。`var self = this;` や `bind(this)` が不要になり、`map` や `then` に渡す短い処理を1行で書けます。逆に、コンストラクタには構文上使えず、`this` で自分のオブジェクトを触るメソッドには向きません。

### アロー関数とfunctionはどちらが速いですか？

どちらが速いかを示す公式の基準はなく、速度差は実行環境と処理内容に依存します。選ぶ基準は `this` の扱いと制約にし、性能が問題になる箇所は対象環境で計測して判断します。メモリで差が出るのは、クラスフィールドにアロー関数を置いてインスタンスを大量に作る場合で、条件は「クラスフィールドのアロー関数とメソッドの違い」に書いています。

### アロー関数はどの環境から使えますか？

MDNの互換性情報では、2016年9月以降すべての主要ブラウザーで使えます。現行のブラウザとNode.jsではそのまま動き、変換は要りません。Internet Explorer 11 を対象に含む古い案件だけ、BabelでES5に変換します。

## 関連記事

- [React Compilerとは？Vite・Next.js・Expoでの導入とRust版・ESLint・useMemoの扱い【2026年10月】](/tech/details/9415/)
- [TypeScript 6.0とは｜5から6への移行手順とts5to6・7.0との違い【6.0.3対応】](/tech/details/11066/)
- [関数型プログラミングとは？純粋関数・不変性・高階関数をTypeScriptの実例で解説](/tech/details/4841/)
- [PHP 8.5の変更点と新機能｜8.4との違い・非推奨・性能を実行結果で確認【8.5.12対応】](/tech/details/8179/)
- [Javaラムダ式の使いどころ｜Stream APIで効く場面と避ける場面をJava 25で実測](/tech/details/2598/)

---

出典: [アロー関数とは？functionとの違い・thisの挙動と使い分け【TypeScript・React・PHP】](<https://www.issoh.co.jp/tech/details/3575/>)（株式会社一創）
