クロージャ(Closure)のしくみとは?―JavaScript初心者のためのやさしい解説
こんにちは。ゆうせいです。
JavaScriptを学んでいると、こんなコードに出会うことがあります。
function outer() {
let message = "こんにちは";
function inner() {
console.log(message);
}
return inner;
}
const greet = outer();
greet(); // → こんにちは
「えっ?outer()
の中でしか宣言されてないmessage
が、外に出た関数から使えてるの!?」「これってどういうこと?」
この「中の関数が、外の変数を記憶している」という不思議な現象こそが クロージャ(Closure) の正体です。
今回は、クロージャのしくみ・なぜ使われるのか・どんな場面で便利なのかを、丁寧に解説します。
クロージャとは?一言でいうと…
クロージャとは、「関数が、定義されたときのスコープ(変数の情報)を“記憶している”状態」のことです。
つまり、関数の外側で宣言された変数を“覚えている”関数のことなんです。
どうしてそんなことができるの?
JavaScriptでは、関数が定義されたときの「スコープ(変数の有効範囲)」を、関数が実行されるときまで保持するしくみがあります。
これを 「スコープチェーン」 といいます。
function outer() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
const counter = outer();
counter(); // 1
counter(); // 2
上記では count
は outer()
の中で定義された変数ですが、counter()
(inner関数)がずっとそれを覚えているため、毎回1ずつ増えていくのです!
図で理解:クロージャの構造
outer()
├── count(スコープ内に存在)
└── inner()(この中からcountを参照)
↑
関数がスコープを“記憶”している!
なぜクロージャが使われるの?
✅ 1. データのカプセル化(外部から直接変更できない)
function createCounter() {
let count = 0;
return {
increment: function () {
count++;
return count;
},
get: function () {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.get()); // 1
count
という変数は関数の外からは直接アクセスできないため、安全に管理できます。
✅ 2. 状態を“覚えておく”処理が書ける
function createGreeter(name) {
return function () {
console.log("こんにちは、" + name + "さん!");
};
}
const greetTaro = createGreeter("太郎");
const greetHanako = createGreeter("花子");
greetTaro(); // → こんにちは、太郎さん!
greetHanako(); // → こんにちは、花子さん!
ここでは、name
の値がそれぞれの関数に記憶されている=クロージャの仕組みです。
数式的に考えると…
通常の関数:
f(x) = x + 1
クロージャ的な関数:
f(y) = (x) => x + y
ここで y
を外側のスコープから固定して、関数を返すという構造になっています。
よくある落とし穴:for文とクロージャ
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// → 3, 3, 3
「えっ!?なんで 0,1,2
じゃないの?」という例。
これは、var
で宣言された変数 i
が1つしかないスコープに属していて、あとから参照されたときの値(3)だけが使われるため。
✅ let
を使うと個別にクロージャが作られて解決できます:
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
// → 0, 1, 2
まとめ:クロージャの本質とは?
ポイント | 内容 |
---|---|
何をする? | 関数が定義時のスコープを覚えている |
なぜ使う? | 状態保持・情報の隠蔽・柔軟な関数生成 |
いつ作られる? | 関数が別の関数の内部で定義され、返されるとき |
よくある用途 | カウンター、イベントハンドラ、カスタムAPI、非同期処理のラッピングなど |
今後の学習のヒント
クロージャを使いこなすために、次のテーマも学んでおきましょう!
- スコープとスコープチェーンの仕組み
- 即時関数(IIFE)とクロージャの関係
- 高階関数との組み合わせ
- JavaScriptのモジュールパターン
クロージャは最初は「なんとなく」で構いません。
でも理解すればするほど、「この仕組みのおかげでJavaScriptはここまで柔軟なんだ」と感じられるはずです。
ぜひ、たくさん書いて、手と頭で覚えていきましょう!
セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク
投稿者プロフィール
