概要
JavaScriptでは、関数を定義する方法が複数存在する:
-
function
宣言(Function Declaration) - 関数式(Function Expression)
- アロー関数(Arrow Function)
一見どれも「関数を作るだけ」のように見えるが、
実際には スコープ、this、巻き上げ、再定義可能性 など、明確に異なる仕様を持っており、設計目的に応じて選ぶ必要がある構文である。
1. function
宣言
function greet(name) {
return `Hello, ${name}`;
}
✅ 特徴:
- 巻き上げ(hoisting)される → 定義より前でも使用可
- 名前がスコープに登録される
- 再定義しやすい(特にグローバルでは注意)
2. 関数式(Function Expression)
const greet = function(name) {
return `Hello, ${name}`;
};
✅ 特徴:
- 式の一部として関数を定義する
- 巻き上げされない
- const/let と組み合わせることで再代入を防げる
- 即時実行関数(IIFE)にも使われる
3. アロー関数(Arrow Function)
const greet = (name) => `Hello, ${name}`;
✅ 特徴:
-
this
を自動的に外側から継承 - bind不要、コールバックやクロージャとの相性が良い
- コンストラクタとしては使えない(
new
不可) -
arguments
オブジェクトを持たない
構文的・設計的な違い比較
項目 | 宣言関数 | 関数式 | アロー関数 |
---|---|---|---|
巻き上げ | ✅ あり | ❌ なし | ❌ なし |
this の挙動 |
呼び出し元に依存 | 呼び出し元に依存 | 外側の this を継承 |
コンストラクタ使用 | ✅ 可能 | ✅ 可能 | ❌ 不可 |
arguments 利用 |
✅ 使用可 | ✅ 使用可 | ❌ 不可 |
構文の簡潔さ | 通常 | 中間 | ✅ 最短 |
再代入の防止(const) | ❌ 不可 | ✅ 可 | ✅ 可 |
使用判断フロー
① 関数を再利用 or 上位スコープから呼び出す? → function 宣言
② 再代入不可 & this が必要? → 関数式 + const
③ this を明示的に制御したい? → アロー関数
④ コンストラクタ関数として使用? → function 宣言 or 関数式
⑤ コールバック処理? → アロー関数が最適
実務ユースケース
✅ this を明示的に固定したい場合(アロー関数)
class Button {
constructor(label) {
this.label = label;
document.addEventListener('click', () => {
console.log(this.label); // ✅ 外の this を参照
});
}
}
✅ 巻き上げを活用する(宣言関数)
// 呼び出しが先でもOK
greet('Toto');
function greet(name) {
console.log(`Hi, ${name}`);
}
✅ IIFE(即時実行関数)によるスコープ分離(関数式)
(function() {
const secret = 'hidden';
console.log(secret);
})();
よくある落とし穴
❌ アロー関数はメソッド定義に向かない
const obj = {
name: 'Toto',
greet: () => {
console.log(this.name); // ❌ undefined
}
};
→ ✅ 通常の関数式または宣言関数を使うべき
❌ 関数宣言の再定義によるバグ
function log() { console.log('A'); }
function log() { console.log('B'); } // 上書きされる
log(); // 'B'
→ ✅ const + 関数式で防げる
結語
関数の定義方法は、単なる書き方の違いではない。
それは 責務・スコープ・バインディング・挙動 を設計する構文的選択である。
- 再利用性と可読性 →
function
宣言 - スコープ限定と制御性 → 関数式 + const
- コールバックとクロージャ → アロー関数
構文を選ぶとは、「どのような関数を設計したいか」を定義すること。
“何を書くか” より “なぜその書き方にしたのか” を常に意識することが、プロフェッショナルな設計の第一歩である。