ブロックスコープって何者?
ブロックスコープは、
「{}(ブロック)の中だけで有効な“ミニスコープ”」 のことです。
if、for、while、単なる {} など、
波カッコで囲まれた範囲ごとに「その中だけで見える変数の部屋」ができます。
そして、let と const はこの「ブロックスコープ」に従います。
ここが、昔の var と決定的に違うポイントです。
一番シンプルなブロックスコープの例
if 文の中だけで有効な変数
if (true) {
let x = 10;
console.log("ブロック内:", x); // 10
}
console.log("ブロック外:", x); // エラー: x is not defined
JavaScriptx は if (true) { ... } の {} の中で宣言されています。
この {} が「ブロックスコープ」です。
その中では x が見えますが、
外に出ると x は存在しません。
ここが重要です。
「let / const で宣言した変数は、その {} の中だけで有効」
これがブロックスコープの基本ルールです。
for 文とブロックスコープ
ループ変数はループの外に漏れない
for (let i = 0; i < 3; i++) {
console.log("ループ内:", i);
}
console.log("ループ外:", i); // エラー: i is not defined
JavaScripti は for 文のブロックの中だけで有効です。
ループが終わったあと、外から i を触ることはできません。
これが var だとこうなります。
for (var j = 0; j < 3; j++) {
console.log("ループ内:", j);
}
console.log("ループ外:", j); // 3(見えてしまう)
JavaScriptvar は「関数スコープ」であり「ブロックスコープを無視する」ので、for の外からも j が見えてしまいます。
今どき var を避けるべき理由のひとつが、
この「ブロックスコープを作らない」という性質です。
ネストしたブロックスコープ
内側から外側は見える、外側から内側は見えない
let a = 1;
{
let b = 2;
{
let c = 3;
console.log(a, b, c); // 1 2 3
}
console.log(a, b); // 1 2
// console.log(c); // エラー: c is not defined
}
console.log(a); // 1
// console.log(b); // エラー: b is not defined
JavaScriptスコープは「入れ子」になります。
内側のブロックからは、
外側の変数(a, b)が見えます。
でも、外側から内側の変数(c や b)は見えません。
ここが重要です。
「内側から外側は見えるが、外側から内側は見えない」
これは関数スコープと同じルールで、ブロックスコープにもそのまま当てはまります。
ブロックスコープがなぜ大事なのか
一時的な変数を“外に漏らさない”ため
例えば、条件付きで何かを計算するコード。
let result;
if (Math.random() > 0.5) {
let temp = 10;
result = temp * 2;
} else {
let temp = 20;
result = temp * 3;
}
console.log(result);
// console.log(temp); // エラー: temp is not defined
JavaScripttemp は「そのブロックの中でだけ使う一時的な変数」です。
外から触る必要はありません。
ブロックスコープのおかげで、temp は外に漏れず、安全に閉じ込められています。
もしこれが全部グローバルや関数スコープに出ていたら、
他の場所から temp をうっかり上書きしてしまうかもしれません。
ここが重要です。
ブロックスコープは「変数の寿命と見える範囲を最小限にする」ための仕組み。
スコープを狭くすることは、そのままバグのリスクを減らすことにつながります。
実務でよくある「ブロックスコープのありがたみ」
ループ内でのコールバックと let
昔よくあった罠がこれです。
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}
// 3 3 3 と出る
JavaScriptvar はブロックスコープを持たないので、
ループが終わった時点で i は 3。
その同じ i を3回参照してしまいます。
let を使うと、
各ループごとに「そのループ専用の i」がブロックスコープで作られます。
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 100);
}
// 0 1 2 と出る
JavaScriptここが重要です。let が「ループごとに別々の i を持てる」のは、
ブロックスコープのおかげ。
非同期処理と組み合わせたときに、バグを防いでくれます。
単なる {} でもブロックスコープを作れる
意図的に“囲って”スコープを分ける
if や for でなくても、
単に {} で囲むだけでブロックスコープを作れます。
{
const message = "ここだけのメッセージ";
console.log(message); // OK
}
console.log(message); // エラー: message is not defined
JavaScript「この変数はこの数行でしか使わない」
というときに、あえてブロックで囲んでスコープを狭める、
という書き方もできます。
モジュールや関数が前提の今どきコードでは出番は少なめですが、
「{} がスコープを作る」という感覚をつかむには良い練習です。
初心者として「ブロックスコープ」で本当に押さえてほしいこと
ブロックスコープは、
「{} の中だけで有効なスコープ」 であり、let / const はこのルールに従う、ということ。
if、for、while、単なる {} など、
どのブロックでも同じようにスコープができる。
内側から外側は見えるけど、
外側から内側は見えない。
これを意識すると、
一時的な変数を外に漏らさない
ループ変数が外に残らない
同じ名前の変数を別々のブロックで安心して使える
といったメリットが得られます。
コードを書くとき、
「この変数、本当はこのブロックの中だけでよくない?」
と一度問いかけてみてください。
その瞬間から、
あなたは「なんとなく変数を置く人」ではなく、
「スコープを設計しているプログラマー」 になっていきます。
