TL

クロージャとスコープ

スコープは変数が見える範囲、クロージャは関数が定義時の外側の変数を“閉じ込めて”覚え続ける仕組み。状態を持つ関数を作れます。

中級クロージャスコープJavaScript最終更新: 2026-06-06
TL;DR要点だけ先に
  • 1.スコープとは変数が参照できる範囲で、グローバル・関数・ブロックの階層で決まります。
  • 2.クロージャは関数が定義された場所の外側変数を保持し続ける仕組みで、状態を閉じ込められます。
  • 3.ループ内で変数を共有すると意図しない値を全クロージャが参照する罠があり、ブロックスコープで回避します。

スコープ:変数が見える範囲

スコープとは、ある変数を「どこから参照できるか」という範囲のことです。範囲を区切ることで、名前の衝突を防ぎ、変数の影響を局所化できます。多くの言語は次の3階層を持ちます。

  • グローバルスコープ — プログラム全体から見える。便利だが、どこからでも書き換えられて事故のもと。
  • 関数スコープ — その関数の中だけで有効。引数や関数内で宣言した変数。
  • ブロックスコープ{ } の中だけで有効。iffor の内側など。

内側からは外側の変数が見えますが、外側から内側の変数は見えません。この「内→外は見える」性質がクロージャの土台になります。

const g = "global";
function outer() {
  const f = "function";
  if (true) {
    const b = "block";
    console.log(g, f, b); // 3つとも見える(内側から外を参照)
  }
  // console.log(b); ← ここでは b は見えない(エラー)
}

var と let の違い

JavaScript では宣言キーワードでスコープが変わります。var は関数スコープ、letconst はブロックスコープです。この違いが後述のループの罠に直結します。

キーワードスコープ再代入備考
var関数スコープブロックを無視する。巻き上げあり
letブロックスコープ現在の標準的な書き方
constブロックスコープ不可再代入しない値はこちらを優先
まず const、必要なら let

再代入しない変数は const、する変数だけ let にすると、変更箇所が読み手に伝わり、意図しない上書きも防げます。var は新規コードでは基本的に使いません。

クロージャ:外側の変数を閉じ込める

クロージャとは、関数が「定義された場所の外側の変数」を覚えたまま持ち運ぶ仕組みです。関数を呼ぶたびに値が消えるのではなく、外側の変数を生かし続けます。これにより、関数が内部に状態を持てます。

function makeCounter() {
  let count = 0;            // 外側のローカル変数
  return function () {
    count += 1;             // 外側の count を覚えている
    return count;
  };
}
const next = makeCounter();
next(); // 1
next(); // 2  ← count が保持され続けている

makeCounter() の実行はとうに終わっているのに、返された関数は count を握り続けます。これがクロージャです。count は外から直接触れないため、カプセル化された状態としても働きます。

ループ内クロージャの罠

クロージャで最も有名なつまずきが、ループの中で関数を作るケースです。var を使うと、各関数が同じ1つの変数を共有してしまいます。

const fns = [];
for (var i = 0; i < 3; i++) {
  fns.push(function () { return i; });
}
fns[0](); // 0 ではなく 3 が返る!

ループ終了後 i3 になっており、3つの関数すべてが同じ i を見ているため、全部 3 を返します。var が関数スコープで、毎回の繰り返しで変数が共有されるのが原因です。

共有か、毎回新規か

var は1個の変数を全員で共有します。let繰り返しごとに新しい変数を作るため、各クロージャが当時の値を覚えます。下のように let へ変えるだけで期待どおり 0, 1, 2 になります。

const fns = [];
for (let i = 0; i < 3; i++) {        // let なら毎回 i が新規に束縛される
  fns.push(function () { return i; });
}
fns[0](); // 0
fns[1](); // 1

まとめ

スコープは「変数が見える範囲」、クロージャは「関数が外側の変数を閉じ込めて覚える仕組み」です。クロージャのおかげで、カウンターや設定のように状態を内側に隠した関数を作れます。ループで関数を量産するときは、変数が共有されるか毎回新規かを意識し、**ブロックスコープ(let)**を使えば古典的な罠を避けられます。

プログラミング Article

クロージャとスコープを実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

クロージャ

比較で見る軸

難易度: intermediate / カテゴリ: プログラミング / タグ数: 3

導入後に効く点

クロージャは関数が定義された場所の外側変数を保持し続ける仕組みで、状態を閉じ込められます。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
intermediate
カテゴリ
プログラミング
タグ数
3

判断チェックリスト

  • 自社の用途が「クロージャ / スコープ」に近いか確認する。
  • 強みである「スコープとは変数が参照できる範囲で、グローバル・関数・ブロックの階層で決まります。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

クロージャスコープJavaScriptクロージャスコープJavaScript
参考: 公式情報