JavaScript アドバンス

JavaScript の関数定義

1. 関数定義と関数宣言の違い

「関数定義(Function Definition)」は関数を定義すること全般を指す一般的な用語です。
一方、「関数宣言(Function Declaration)」は関数を定義するための特定の具体的手法の一つを指します。

関数定義の例には以下のものが含まれます:

  • 関数宣言 (Function declarations)
  • 関数式 (Function expressions)
  • アロー関数 (Arrow functions)

1.1 関数定義の例

// 関数宣言 (Function Declaration)
function myFunction(x, y) {
  return x * y;
}

// 関数式:名前付き (Named Function Expression)
const myFunction = function name(x, y) {
  return x * y;
};

// 関数式:匿名/無名 (Anonymous Function Expression)
const myFunction = function (x, y) {
  return x * y;
};

// アロー関数 (Arrow Function)
const myFunction = (x, y) => x * y;

// Functionコンストラクタ (Function Constructor)
const myFunction = new Function("x", "y", "return x * y");

// オブジェクトのメソッド (Object Method)
const obj = {
  myFunction(x, y) {
    return x * y;
  },
};

2. 関数宣言

これまでのチュートリアルで学んだ通り、関数は以下の構文で「宣言」されます:

function functionName(parameters) {
  // 実行されるコード
}

関数宣言では、function キーワードと「関数名」を使用します。

2.1 関数宣言の記述例

1行で記述する場合:

function myFunction(a, b) {return a * b}

一般的な記述方法:

function myFunction(a, b) {
  return a * b;
}

宣言された関数は、即座に実行されるわけではありません。それらは「後で使用するために保存」され、後で呼び出された(インボークされた)時に実行されます。

また、関数宣言はコード内での宣言箇所の前でも後でも呼び出すことが可能です。

宣言の前に呼び出す例:

let x = myFunction(4, 3);

function myFunction(a, b) {
  return a * b;
}

宣言の後に呼び出す例:

function myFunction(a, b) {
  return a * b;
}

let x = myFunction(4, 3);

3. 関数式

関数式は、関数を変数の中に格納する手法です。
この時の関数は「匿名(名前がない状態)」にすることが可能です。
関数式は、コードがその行に到達した時のみ実行されます。

3.1 関数式の例

const x = function (a, b) {return a * b};

関数式が変数に格納された後は、その変数を関数として使用できます。

const x = function (a, b) {return a * b};

let z = x(4, 3);

4. ホイスティング (Hoisting)

関数宣言は、そのスコープの最上部へホイスティング(巻き上げ)されます。
関数式は、同様の形ではホイスティングされません。

  • 関数宣言: 定義される前でも呼び出すことが可能。
  • 関数式: 定義される前に呼び出すことは不可能。

4.1 ホイスティングの動作例

関数宣言は定義前に呼び出し可能:

const sum = add(2, 3); // 正常に動作する

function add(a, b) {return a + b;}

関数式は定義前に呼び出すとエラーになる:

const sum = add(2, 3); // ⛔ エラーが発生する

const add = function (a, b) {return a + b;};

5. 主な違い

特徴関数宣言 (Function Declaration)関数式 (Function Expression)
構文function キーワードで始まり、関数名が必須となるステートメント。式や代入の一部であり、匿名(名前なし)にすることが可能。
ホイスティングコード実行前にスコープの最上部へ移動されるため、定義前でも呼び出し可能。変数はホイスティングされる可能性があるが(varの場合など)、関数自体の代入は行われないため、定義後のみ呼び出し可能。
柔軟性グローバル、または特定のスコープ全体で利用したい汎用的な関数に適している。コールバック関数、即時実行関数(IIFE)、オブジェクトのプロパティへの代入など、様々なコンテキストで使用可能。

6. 変数に格納された関数

変数に格納された関数は、他のあらゆる値と同じように扱うことができます。

6.1 変数としての利用例

function myFunction(a, b) {
  return a * b;
}

let x = myFunction(4, 3);

JavaScriptの関数は、式の中で使用することも可能です。

function myFunction(a, b) {
  return a * b;
}

let x = myFunction(4, 3) * 2;

7. Function() コンストラクタ

関数は JavaScript の Function() コンストラクタを使用して定義することもできますが、実務で使われることは稀です。

7.1 コンストラクタの例

const myFunction = new Function("a", "b", "return a * b");

let x = myFunction(4, 3);

実際には、関数コンストラクタを使用する必要はありません。上記の例は以下のように記述するのと同等です。

const myFunction = function (a, b) {return a * b};

let x = myFunction(4, 3);

多くの場合、JavaScript において new キーワードの使用は避けることができます。

8. オブジェクトとしての関数

JavaScript の typeof オペレータは、関数に対して "function" を返します。
しかし、JavaScript の関数は「オブジェクト」として記述するのが最も正確です。
JavaScript の関数は、プロパティとメソッドの両方を持っています。

8.1 arguments.length プロパティ

arguments.length プロパティは、関数が受け取った「引数の数」を返します。

function multiply(a, b) {
  return arguments.length;
}

// 0 を返す
multiply();

// 2 を返す
multiply(a, b);

8.2 toString() メソッド

toString() メソッドは、関数を文字列として返します。

function multiply(a, b) {
  return a * b;
}

let text = multiply.toString();