プログラミング基礎概念

クロージャ くろーじゃ

関数スコープ変数のキャプチャレキシカルスコープ高階関数JavaScript
クロージャって何ですか?

簡単に言うとこんな感じ!

関数が「自分が生まれた場所の変数」を、外に出た後もずっと覚えていられる仕組みだよ!引越しした後も地元の友達の連絡先を持ち歩いてる感じ。これがクロージャってこと!


クロージャとは

クロージャ(Closure)とは、関数がその関数が定義されたスコープ(変数の有効範囲)の変数を、スコープを抜け出した後も参照し続けることができる仕組みのことです。平たく言うと、「関数が自分の”生まれ故郷”の変数を記憶している状態」です。

通常、関数の実行が終わると、その中で使われていた変数はメモリから消えてしまいます。しかしクロージャを使うと、内側の関数が外側の関数の変数を”閉じ込めて(close over)“保持し続けることができます。この「閉じ込める」という動作が名前の由来です。

クロージャは JavaScriptPythonRubySwift など多くのモダンな言語でサポートされており、状態の保持・プライベート変数の実現・コールバック関数の実装など、実務でも非常に頻繁に使われる重要な概念です。


クロージャの仕組みと構造

クロージャが成立するには、次の3つの要素が揃う必要があります。

要素説明例(JavaScript)
外側の関数変数を持つ関数function outer()
内側の関数外側の変数を参照する関数function inner()
変数のキャプチャ外側の変数を内側の関数が記憶している状態outer が終了しても count が残る

以下のコードで動きを確認できます(JavaScript):

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

makeCounter() の実行が終わっても、返された内側の関数は count を覚え続けます。counter を何度呼んでも count は加算され続けます。これがクロージャです。

語呂合わせで覚えよう

「クロージャ=クローゼットに変数を閉まっておく関数」

クローゼット(closet)の語感に近いですね。関数がクローゼットの中に変数をしまい込んで、外から見えないけれど自分だけはいつでも取り出せる、というイメージです。

クロージャが活躍する場面

【よく使われるパターン】

1. カウンターや状態の保持
   └ 変数を外に露出せずに内部でだけ管理したいとき

2. プライベート変数の擬似実現
   └ JavaScriptなど「クラスの非公開変数」が難しい言語で代替

3. コールバック・イベントハンドラ
   └ ボタンを押したときに「どのIDのデータか」を記憶しておく

4. 関数ファクトリ(関数を生成する関数)
   └ 「5倍にする関数」「10倍にする関数」を動的に作る

歴史と背景

  • 1960年代 — クロージャの概念はLISP言語の研究から生まれた。関数型プログラミングの基礎理論として登場
  • 1975年 — Schemeがクロージャを言語仕様として正式に採用。「レキシカルスコープ(静的スコープ)」と組み合わせて普及
  • 1990年代 — 関数型プログラミング言語Haskell・ML系)がクロージャを活用。一方、C言語Javaなどの主流言語では非対応だったため、一般には難解な概念とみなされていた
  • 2000年代 — JavaScriptがWebの主役になると、イベント処理やAjax通信でクロージャが必須の知識に。「JavaScriptを理解するにはクロージャを理解せよ」と言われるほど重要な概念になる
  • 2010年代以降 — Python・Ruby・Swift・KotlinRustなどほぼすべてのモダン言語がクロージャをサポート。プログラミング教育でも必修トピックとして定着

スコープとの関係・関連概念の比較

クロージャを理解するうえで、スコープ(変数の有効範囲) の概念は切り離せません。

外側のスコープ(outer function) let count = 0 外側の変数(ローカル変数) 内側のスコープ(inner function = クロージャ) count++ ← 外側の変数を参照・変更できる makeCounter() が終了した後も count を記憶し続ける キャプチャされた変数(Captured Variable) count は GC(ガベージコレクション)で回収されず クロージャが生きている限りメモリに保持される

クロージャと似た概念の比較

概念説明クロージャとの違い
スコープ変数が有効な範囲クロージャはスコープを”またいで”変数を保持する仕組み
レキシカルスコープ変数のスコープがコードを書いた位置で決まることクロージャが成立するための前提条件
コールバック関数別の関数に渡して後で呼び出す関数コールバックがクロージャになることが多い
高階関数関数を引数に取ったり返したりする関数クロージャは高階関数と組み合わせて使われる
クラス(OOP)データと操作をまとめる仕組みクロージャはクラスなしで「状態+操作」を実現できる

Python でのクロージャ例

def make_multiplier(n):
    def multiplier(x):   # n をキャプチャしている
        return x * n
    return multiplier

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))  # → 10
print(triple(5))  # → 15

n という変数が make_multiplier を抜けた後も multiplier 関数の中に保持されています。doubletriple はそれぞれ異なる n を記憶した別々のクロージャです。


関連用語

  • スコープ — 変数が参照できる有効範囲のこと。クロージャを理解するための前提知識
  • レキシカルスコープ — 変数のスコープがコードの書かれた位置によって静的に決まる仕組み
  • 高階関数 — 関数を引数として受け取ったり、関数を返したりする関数
  • コールバック関数 — 別の関数に引数として渡して後で実行される関数。クロージャと組み合わせて多用される
  • ガベージコレクション — 不要になったメモリを自動回収する仕組み。クロージャが変数を保持するとGCの対象外になる
  • 関数型プログラミング — 関数を主役にするプログラミングスタイル。クロージャはその中核的概念
  • イベントハンドラ — ボタンクリックなどのイベント発生時に呼ばれる関数。クロージャとして実装されることが多い