JavaScript 入門

JavaScript ファンクションデクラレーションとファンクションエクスプレッション

ファンクションデクラレーション(Function Declarations)とファンクションエクスプレッション(Function Expressions)は、JavaScriptでファンクションを定義するための2つの方法です。どちらも「再利用可能なコードブロックを作成する」という目的は同じですが、シンタックスや、何よりもコード実行時の処理方法において顕著な違いが存在します。

これらの違いを理解することは、クリーンで効率的、かつ予測可能なJavaScriptコードを書くために不可欠です。本章では、これら2つのアプローチの細かな違いを深く掘り下げ、それぞれのユニークな特徴を強調しながら、どのようなシーンでどちらを優先すべきかをデモンストレーションします。

1. ファンクションデクラレーション

ファンクションデクラレーションは、JavaScriptでファンクションを定義する最も一般的で直接的な方法です。function キーワードに続き、ファンクション名、括弧内のパラメーターリスト、そして波括弧内のファンクション本体を記述するのが特徴です。

1.1 シンタックスと構造

ファンクションデクラレーションの基本的なシンタックスは以下の通りです。

function functionName(parameter1, parameter2, ...) {
  // ファンクション本体 - 実行されるコード
  return value; // オプションのリターン文
}
  • function キーワード: ファンクションデクラレーションの開始を示すキーワードです。
  • functionName: ファンクションを呼び出したり参照したりするための識別子(名前)です。
  • parameter1, parameter2...: ファンクションが受け取る入力値(パラメーター)です。これらはオプションであり、パラメーターを持たないファンクションも作成可能です。
  • { ... }: 波括弧はファンクション本体を包み、呼び出し時に実行されるJavaScriptステートメントを保持します。
  • return value: ファンクションが返す値を指定します。return 文がない場合、ファンクションは暗黙的に undefined を返します。

1.2 ホイスティング (Hoisting)

ファンクションデクラレーションの重要な特徴は、これらがホイスティング(巻き上げ)されることです。これは、JavaScriptのインタプリタがコードを実行する前に、ファンクションのデクラレーションをそのスコープのトップに移動させることを意味します。

そのため、コード内で実際にファンクションをデクラレーションする前であっても、そのファンクションを呼び出すことができます。

// デクラレーションの前にファンクションを呼び出す
console.log(add(5, 3)); // 出力: 8

// ファンクションデクラレーション
function add(a, b) {
  return a + b;
}

この例では、add ファンクションが呼び出しの後にデクラレーションされているにもかかわらず、コードはエラーなく実行されます。これは、ファンクションデクラレーションがスコープのトップにホイスティングされたためです。

1.3 示例:長方形の面積を計算する

// 長方形の面積を計算するためのファンクションデクラレーション
function calculateRectangleArea(length, width) {
  return length * width;
}

// ファンクションを呼び出し、リザルトを保存
let area = calculateRectangleArea(10, 5);
console.log("長方形の面積は: " + area); // 出力: 長方形の面積は: 50

この例では、calculateRectangleAreaファンクションデクラレーションです。2つのパラメーター lengthwidth を受け取り、それらの積(面積)を返します。

2. ファンクションエクスプレッション

ファンクションエクスプレッションは、JavaScriptでファンクションを定義するもう一つの方法を提供します。この方法では、ファンクションがより大きなエクスプレッションの一部として定義され、通常は代入エクスプレッションとして扱われます。

2.1 シンタックスと構造

ファンクションエクスプレッションの基本的なシンタックスは以下の通りです。

let functionName = function(parameter1, parameter2, ...) {
  // ファンクション本体 - 実行されるコード
  return value; // オプションのリターン文
};
  • let functionName =: ファンクションをバリアブルに代入します。let(または const, var)キーワードを使用してバリアブルをデクラレーションします。
  • function(parameter1, parameter2, ...): これはアノニマスファンクション(匿名関数)です。function キーワードの後に名前がないため、このように呼ばれます(ただし、命名ファンクションエクスプレッションも可能です)。
  • { ... }: 波括弧が実行されるコードブロックを包みます。
  • return value: ファンクションのリターン値を指定します。

2.2 ホイスティング(またはその欠如)

ファンクションデクラレーションとは異なり、ファンクションエクスプレッションはホイスティングされません。つまり、コード内で実際にファンクションエクスプレッションを定義する前に、それを呼び出すことはできません。これを行おうとすると、ReferenceError が発生します。

// 定義の前にファンクションを呼び出す
// console.log(multiply(4, 6)); // これは ReferenceError: Cannot access 'multiply' before initialization を引き起こします

// ファンクションエクスプレッション
let multiply = function(a, b) {
  return a * b;
};

console.log(multiply(4, 6)); // 出力: 24

この例で、定義前の呼び出しをコメント解除すると、ReferenceError に遭遇します。実行時に multiply バリアブルがまだ初期化されていないためです。

2.3 アノニマスと命名ファンクションエクスプレッション

ファンクションエクスプレッションは、アノニマス(匿名)にすることも、名前を付けることもできます。

アノニマスファンクションエクスプレッションは、前の例のように function キーワードの直後に名前を持ちません。

一方で、命名ファンクションエクスプレッションは独自の名称を持ちます。

// 命名ファンクションエクスプレッション
let factorial = function calculateFactorial(n) {
  if (n <= 1) {
    return 1;
  } else {
    return n * calculateFactorial(n - 1); // ファンクション名を使用して再帰呼び出し
  }
};

console.log(factorial(5)); // 出力: 120

この例では、calculateFactorial がファンクションエクスプレッションの名称です。ファンクションfactorial バリアブルに代入されていますが、ファンクション自体が名前を持っているため、再帰処理やデバッグに役立ちます。ただし、この calculateFactorial という名前はファンクション内部からのみアクセス可能です。

2.4 示例:数値の二乗を計算する

// 数値の二乗を計算するためのファンクションエクスプレッション
let square = function(number) {
  return number * number;
};

// ファンクションを呼び出し、リザルトを保存
let squaredValue = square(7);
console.log("7 の二乗は: " + squaredValue); // 出力: 7 の二乗は: 49

ここでは、square バリアブルに代入されたファンクションエクスプレッションが、入力された数値の二乗を計算して返しています。

3. 決定的な違いのまとめ

特性ファンクションデクラレーションファンクションエクスプレッション
シンタックスfunction name() { ... }let name = function() { ... };
ホイスティングされる (定義前に呼び出し可能)されない (定義後にのみ呼び出し可能)
ネーミング名前は必須アノニマスまたは命名が可能
ユースケース汎用的なトップレベルファンクションバリアブルへの代入、コールバック、クロージャ

4. 実践的な考慮事項とユースケース

4.1 デクラレーションとエクスプレッションの選択

どちらを選択するかは、多くの場合、具体的なコンテキストやコードスタイルの好みに依存します。

  • ファンクションデクラレーション: スコープ内のどこからでも呼び出せる汎用的なファンクションを定義したい場合に適しています。スクリプト全体で共通して使用するユーティリティなどに最適です。
  • ファンクションエクスプレッション: ファンクションをバリアブルに代入したり、別のファンクションの引数として渡したり(コールバック)、クロージャを作成したりする場合に使用します。ファンクションのスコープやライフサイクルをより精密にコントロールしたい場合に非常に有用です。

4.2 即時実行ファンクションエクスプレッション (IIFE)

詳細は別の機会に譲りますが、IIFE(Immediately Invoked Function Expression)は常にファンクションエクスプレッションを使用して作成されます。定義された直後に実行されるため、バリアブルホイスティング問題を避け、クリーンな独立したスコープを作成するのに役立ちます。

(function() {
  let message = "IIFE からの挨拶!";
  console.log(message); // 出力: IIFE からの挨拶!
})();

4.3 コールバックファンクション (Callbacks)

非同期処理や配列メソッドを使用する際、ファンクションエクスプレッションは頻繁にコールバックとして利用されます。

let numbers = [1, 2, 3, 4, 5];

// ファンクションエクスプレッションを map メソッドのコールバックとして使用
let squaredNumbers = numbers.map(function(number) {
  return number * number;
});

console.log(squaredNumbers); // 出力: [1, 4, 9, 16, 25]

この例では、アノニマスファンクションエクスプレッションが map メソッドのコールバックとして渡され、配列の各要素に対して処理を適用しています。