【すこーぷ】

スコープ とは?

最終更新:
💡 この名前は、ここから参照できる?

プログラム中で変数などの名前を参照できる範囲。JavaScriptを例に、関数・ブロック・モジュール、同名変数の隠れ方、クロージャーとの関係を解説します。

📌 このページのポイント
スコープ:同じ名前でも別の変数JavaScript:外側の範囲let count = 1;1内側のブロックlet count = 2;2ここで count を読む → 2ブロックの後で count を読む → 1内側の宣言が、外側の名前を隠す外側の変数に代入したわけではない
外枠と内枠は名前を参照できる範囲です。内側のlet宣言は別の変数を作るため参照結果が変わります。名前を参照する範囲と、値が保持される期間は別の話です。
ひよこ ひよこ
スコープは、変数が使える場所のこと?
ペンギン先生 ペンギン先生
そうだね。正確には、変数や関数などの名前を参照できる範囲だ。別の関数で同じ名前を使っても区別できるなど、名前と処理の関係を整理する仕組みになる。
ひよこ ひよこ
グローバルなら、どのファイルからも見える?
ペンギン先生 ペンギン先生
何でも見えるわけではない。JavaScriptでも、通常のスクリプトとモジュールで範囲が違う。モジュールの先頭で宣言した名前は、そのモジュールの範囲になる。他のモジュールへ渡すにはexportやimportなどを使うよ。
ひよこ ひよこ
内側から外側の変数は見える?
ペンギン先生 ペンギン先生
JavaScriptでは、内側の関数などから外側の名前を参照できる。ただし内側で同じ名前を宣言すると、その名前が外側を隠す。これをシャドーイングと呼ぶんだ。外側の値が消えたという意味ではないよ。
ひよこ ひよこ
図のcountは、なぜ2と1になるの?
ペンギン先生 ペンギン先生
外側でlet count = 1、内側のブロックで別のlet count = 2を宣言した例だよ。内側でcountを読むと2、ブロックの後で外側のcountを読むと1になる。内側の宣言は、外側の変数への代入とは違う。
ひよこ ひよこ
varとletの範囲は同じ?
ペンギン先生 ペンギン先生
varは、関数の中ならその関数の範囲になり、ifなどのブロックだけでは区切られない。letとconstはブロックにも範囲を持つ。letやconstを宣言・初期化より前に読むと、同じ範囲内でもReferenceErrorになるよ。
ひよこ ひよこ
範囲を抜けた変数は、メモリから消える?
ペンギン先生 ペンギン先生
必ずそうなるわけではない。例えば返した関数が外側の変数を参照するクロージャーでは、元の関数が終わった後もその状態を使える。名前が直接見える範囲と、状態が保持される期間は分けて考えよう。
もっと詳しく知りたい人へ

letを宣言する前なら、外側の同名変数を読める?

同じブロックにletの宣言がある場合、その名前はブロックの開始から内側の宣言に対応します。ただし宣言・初期化に到達するまではtemporal dead zone(TDZ)にあり、参照するとReferenceErrorです。外側の同名変数へ自動的に戻って探すわけではありません。

スコープを小さくすれば、変更は完全に防げる?

完全には防げません。名前の影響範囲を整理する助けになりますが、関数を通して状態を読み書きできたり、複数箇所が同じオブジェクトを参照していたりします。スコープ・値の変更可能性・アクセス方法は別々に確認します。また、他の言語にJavaScriptの規則をそのまま当てはめないようにします。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「スコープ」って出てきたら「プログラム中で名前を参照できる範囲」と思えばだいたいOK!
📖 おまけ:英語の意味
「Scope」 = 範囲
💬 プログラミングでは、変数などの名前をどこから参照できるかという範囲を表します。ここではJavaScriptの規則を例に説明します。

参考資料

← 用語集にもどる