JavaScript | 第5章「関数」

javascrpit JavaScript
スポンサーリンク

初心者向けに「関数って何?」「どんな種類がある?」「どう使うの?」を、例を交えて分かりやすく説明する。まず大枠をつかんで、それから少しずつ深めていこう。

関数とは何か(Function の基本)

  • 関数とは、一定の処理(命令のまとまり)をひとまとめにして “名前” をつけ、必要な時に呼び出して使えるようにしたもの。
  • 他の言語でいう「サブルーチン」や「メソッド」に近い考え方。
  • JavaScript における関数は、「入力を受け取って処理し、出力を返す」というスタイルをとることが多い。
  • 関数は “値” として扱える(第一級オブジェクト / first-class objects)ので、変数に代入できたり、他の関数の引数に渡せたり、戻り値として返したりできる。

例:ある数を 2 倍にする処理を関数にする

function double(x) {
  return x * 2;
}
console.log(double(5)); // 10
JavaScript

関数の定義方法(関数の書き方)

関数を定義する方法には主に以下のようなスタイルがある。

方法構文特徴・注意点
関数宣言(Function declaration)function 関数名(引数1, 引数2, …) { … }宣言時点で関数が有効になる(ホイスティング)
関数式(Function expression)const f = function(引数…) { … };無名関数を変数に代入する形。宣言前の呼び出しはできない
名前付き関数式const f = function name(引数) { … };デバッガで名前が出やすい、自分自身を呼び出しやすい
アロー関数式(Arrow functions)const f = (引数) => { … } または省略形 const f = x => x * 2関数式の簡潔記法。this の扱いが少し特殊

ホイスティング(関数宣言の巻き上げ)

関数宣言の場合、JavaScript の解釈時に関数定義がスコープの先頭に “巻き上げられる(hoisting)” ので、関数を定義する前に呼び出しても動くことを覚えておくとよい(ただし可読性を考えると、前に定義しておく方が望ましい)。
ただし、関数式やアロー関数にはこのホイスティング特性は適用されない。

引数と戻り値(Parameters / Arguments / Return)

引数(Parameters / Arguments)

  • 関数に渡す値を「引数(arguments)」と呼ぶ。
  • 関数定義側では「パラメータ(parameters)」と呼んだりする。
  • 引数は必ずしも固定数でなく、可変長で受け取ることもできる。
  • JavaScript には arguments オブジェクト(関数内で引数リスト全体を扱うための特別な配列様のオブジェクト)もある(ただし ES6 以降はレスト構文 ...args を使う方が多い)。

例:可変長引数を足し合わせる関数

function sum(...nums) {
  let total = 0;
  for (let n of nums) {
    total += n;
  }
  return total;
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(5, 10));   // 15
JavaScript

戻り値(Return)

  • 処理の結果を返したいときは return 値; を使う。
  • return がない場合は暗黙に undefined を返す。
  • return を途中で使えば、途中で処理を抜けることもできる。

スコープとクロージャ(Scope & Closure)

関数を扱う上でとても重要な概念。初心者にとっては少し難しいけど、理解しておくとプログラム設計が一気に楽になる。

スコープ(Scope)

  • スコープとは、「変数が参照できる有効範囲」のこと。
  • 関数の内部で定義された変数はその関数の内部でしか見えない(ローカル変数)。
  • 関数の外で定義された変数は(適切なスコープ内で)関数内からも参照できる(グローバル変数や外側スコープの変数)。
  • スコープのネスト(入れ子)も可能。

例:

let globalVar = "外";

function outer() {
  let outerVar = "中";
  function inner() {
    let innerVar = "内";
    console.log(globalVar, outerVar, innerVar); // 全て参照できる
  }
  inner();
  console.log(globalVar, outerVar); // innerVar は見えない
}
outer();
JavaScript

クロージャ(Closure)

  • 関数が、その定義されたときのスコープ(環境)を「覚えている」性質のこと。
  • 外側の関数が終了しても、そのスコープの変数を関数の内部から使い続けられる。
  • よく「関数とそのスコープ(環境)の組み合わせ」と表現される。

例:カウンター関数(クロージャ利用)

function makeCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
JavaScript

ここで、makeCounter が終わっても、内部の count の値を保持した状態で返された関数が使えるのはクロージャのおかげ。

関数の応用・発展的な使い方

ここからは少し応用的な話を紹介するけれど、「まずは基本」を押さえてから見るといい。

再帰(Recursion)

関数の中で自分自身を呼び出すこと。例:階乗を求める関数

function factorial(n) {
  if (n <= 1) {
    return 1;
  } else {
    return n * factorial(n - 1);
  }
}
console.log(factorial(5)); // 120
JavaScript

call, apply, bind

関数はオブジェクトなので、callapplybind といったメソッドを用いて、「この関数を呼ぶときに this を特定のオブジェクトにセットする」などの制御ができる。

  • call(thisArg, arg1, arg2, …)
  • apply(thisArg, [arg1, arg2, …])
  • bind(thisArg) は関数を “this を固定した新しい関数” に変える

メソッドとしての関数(オブジェクトのプロパティ関数)

オブジェクトの中に「関数をプロパティとして持つ」ことができ、そういう関数はそのオブジェクトの「メソッド」となる。

const obj = {
  x: 10,
  printX: function() {
    console.log(this.x);
  }
};
obj.printX(); // 10
JavaScript
タイトルとURLをコピーしました