JavaScriptのクロージャとは?仕組みと使い方を基礎から徹底解説

JavaScriptを学習していると、「クロージャ(closure)」という言葉に必ず出会います。
一見すると難しそうに見えますが、仕組みを理解すると関数の理解が一段深まり、実務でも非常に役立つ重要な概念です。
この記事では、クロージャの基本から実践的な使い方まで、基礎をしっかり固められるように解説します。
Contents
クロージャとは何か
クロージャとは、関数が外側のスコープの変数を記憶したまま使える仕組みのことです。
JavaScriptでは、関数は作成されたときのスコープ(変数の環境)を保持します。
そのため、関数の外で定義された変数でも、関数内から参照できます。
クロージャの基本例
まずはシンプルなコードで確認します。
// closure-basic.js
function outer() {
const message = "こんにちは";
function inner() {
console.log(message);
}
return inner;
}
const fn = outer();
fn(); // こんにちはポイント
innerはouterの中で定義されているouterの実行後でも、messageを保持している- これがクロージャの本質
なぜクロージャが成立するのか
JavaScriptの関数は、定義されたときのスコープを保持するという性質を持っています。
そのため、関数が返されたあとでも、元のスコープにアクセスできます。
この仕組みは、以下の記事で解説している関数の基本理解と深く関係しています。
→ JavaScriptの関数とは?基本から使い方まで解説
クロージャのイメージ
クロージャは以下のように考えると理解しやすいです。
- 関数は「変数を覚えた箱」
- 外側の変数を持ったまま動く
つまり、
「関数 + そのときの環境」=クロージャ
という構造になっています。
クロージャの実用例①:カウンター
クロージャは、状態を保持する処理でよく使われます。
// closure-counter.js
function createCounter() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
const counter = createCounter();
counter(); // 1
counter(); // 2
counter(); // 3ポイント
countは外から直接触れない- 関数だけが
countにアクセスできる - 状態を安全に管理できる
クロージャの実用例②:設定を保持する関数
// closure-config.js
function createGreeting(greeting) {
return function (name) {
console.log(greeting + "、" + name + "さん");
};
}
const hello = createGreeting("こんにちは");
const goodMorning = createGreeting("おはよう");
hello("太郎"); // こんにちは、太郎さん
goodMorning("花子"); // おはよう、花子さんポイント
- 引数
greetingを保持している - 同じ関数でも違う設定で使い回せる
クロージャのメリット
状態を安全に管理できる
外部から直接アクセスできない変数を作れるため、意図しない変更を防げます。
関数の再利用性が高まる
設定や条件を保持した関数を作ることで、柔軟な処理が可能になります。
カプセル化ができる
オブジェクト指向でいう「カプセル化」に近い役割を果たします。
クロージャの注意点
メモリに残り続ける
クロージャは外側の変数を保持するため、不要になったら参照を切ることが重要です。
// closure-memory.js
function createData() {
const largeData = new Array(1000000).fill("data");
return function () {
console.log(largeData.length);
};
}
let fn = createData();
fn();
// 不要になったら解放
fn = null;よくある疑問:なぜループで問題が起きるのか
クロージャはループと組み合わせると、意図しない動作になることがあります。
// closure-loop-problem.js
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}
// 3, 3, 3 と出力される解決方法(letを使う)
// closure-loop-fix.js
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}
// 0, 1, 2 と出力されるこの違いは、スコープの仕組みによるものです。
→ JavaScriptのスコープとは?var・let・constの違いを解説
クロージャと非同期処理の関係
クロージャは非同期処理でも重要な役割を持ちます。
// closure-async.js
function fetchData(url) {
return function () {
console.log("取得中:", url);
};
}
const request = fetchData("https://example.com");
request();Promiseやthenなどの理解にもつながります。
→ JavaScriptの非同期処理とは?Promiseとasync/awaitの基礎
→ JavaScriptのthenの使い方
クロージャを使う場面
クロージャは以下のような場面で活躍します。
- カウンターや状態管理
- 設定付き関数の生成
- イベント処理
- 非同期処理の制御
特にイベント処理については、以下の記事で詳しく解説しています。
→ JavaScriptのイベントとは?クリック・入力処理の基本を解説
まとめ
クロージャは、JavaScriptにおける重要な概念のひとつです。
- 関数はスコープを記憶する
- 外側の変数を保持したまま動作する
- 状態管理や再利用性の高い処理に役立つ
最初は難しく感じますが、基本的なコードを繰り返し確認することで理解が深まります。

