まず「ブロックスコープ」を一言でいうと
ブロックスコープは、
「{ ... } のカタマリの中だけで有効な“変数の生息範囲”」 のことです。
JavaScript の let と const で宣言した変数は、
この「ブロック(= {} の中)」を単位にして、
その中だけ見える
外からは見えない
という「見える/見えないの境界」が決まります。
ここが重要です。
「どこからどこまで、その変数が見えるか(使えるか)」を決めるルールがスコープ。
その中でも {} を単位とするものが「ブロックスコープ」。let / const はこのルールに従う。
ブロックとは何か:ただの「{ } のかたまり」
if や for の「かっこ」がブロック
次のコードを見てください。
if (true) {
const message = "こんにちは";
console.log(message); // ここでは使える
}
console.log(message); // エラー:message はここでは定義されていない
JavaScript{ ... } で囲まれた部分(if の中)が「ブロック」です。
この中で宣言された message は、
このブロックの外からは見えません。
同じように、for や while もブロックを作ります。
for (let i = 0; i < 3; i++) {
const text = "ループ中";
console.log(i, text); // ここでは i も text も見える
}
console.log(i); // エラー:i はここでは定義されていない
console.log(text); // エラー
JavaScriptループの {} の中が「ブロック」であり、
その中で宣言された変数はブロックスコープに従って、
ブロックの外には漏れません。
ブロックは単なる「任意の { } 」でもよい
if や for がなくても、
単に {} で囲んだだけでブロックを作れます。
{
const x = 10;
console.log(x); // 10
}
console.log(x); // エラー:x はスコープ外
JavaScriptこの { ... } の中が一つの「ミニ世界」になっていて、
そこで宣言された x は「そのミニ世界専用」の変数です。
ここが重要です。
ブロック = {} で囲まれた範囲。let / const で宣言した変数は、そのブロックの中だけで有効になる。
ブロックの外からは見えないし、触れない。
let / const と var の違い:ブロックスコープがあるかどうか
let / const はブロックスコープ
例をもう一度整理します。
if (true) {
let a = 1;
const b = 2;
console.log(a, b); // 1, 2
}
console.log(a); // エラー
console.log(b); // エラー
JavaScripta も b も、if の中(ブロックの中)でしか使えない変数です。
これは直感に合います。
「この if の条件が true のときだけ使う一時的な変数」
「この for の中だけで使うカウンター」
そういうものはブロックの中に閉じてくれたほうが安心ですよね。
var はブロックを無視する(関数スコープ)
var はブロックスコープを持たない、というのがややこしいところです。
if (true) {
var x = 10;
console.log("中:", x); // 10
}
console.log("外:", x); // 10(えっ…? 見えてしまう)
JavaScriptif の中で宣言したつもりの x が、if の外でも見えてしまいます。
ループでも同じです。
for (var i = 0; i < 3; i++) {
console.log("ループ内:", i);
}
console.log("ループ外:", i); // 3(i が漏れている)
JavaScriptvar は「関数スコープ」で、
「関数の中かどうか」は見るけれど、「ブロックの中かどうか」は見ない
というルールになっています。
ここが重要です。let / const は「ブロックごとに変数の世界を分ける」。var はそれをしないので、意図せず変数が外に漏れてバグの元になる。
だから、今は let / const を使おう、という話につながります。
ブロックスコープが役に立つ場面
その場限りの変数を外に漏らさない
例えば、次のような処理を考えます。
if (user.isAdmin) {
const message = "管理者としてログインしました";
console.log(message);
}
// ここでは message はもう不要
JavaScriptmessage は、「管理者チェックの場面」でだけ使いたいものです。
if の外で使う必要はありません。
ブロックスコープのおかげで、message は if の外からアクセスできないので、
「間違って他の場所で使ってしまう」リスクをなくせます。
同じ名前を「別のブロック」で再利用できる
次のコードを見てください。
{
const value = 1;
console.log("ブロック1:", value); // 1
}
{
const value = 2;
console.log("ブロック2:", value); // 2
}
JavaScript両方とも value という名前ですが、
別々のブロックなので、別々の変数として扱われます。
これは、関数内の for でもよく使います。
for (let i = 0; i < 3; i++) {
console.log("ループ1:", i);
}
for (let i = 0; i < 2; i++) {
console.log("ループ2:", i);
}
JavaScriptどちらも i ですが、
各ループの {} の中だけに存在する i なので、
互いに干渉しません。
ここが重要です。
ブロックスコープがあることで、「その場限りの変数」を外に漏らさずに済む。
結果として、同じ名前も「別のブロックごとに安心して再利用」できる。
ブロックスコープを意識すると、バグが減る理由
「この変数、どこから使われている?」が分かりやすくなる
例えば、ファイルの上のほうにこう書いてあったとします。
let temp = 0;
JavaScriptその後、長いコードの中で 10 回以上 temp が出てくると、
「どこで使っていて、どこで書き換えているのか」を追うのが大変になります。
一方、ブロックスコープをきちんと使うと、
一時的な変数はなるべくブロックの中に閉じ込めてしまいます。
function process() {
{
let temp = calcSomething();
console.log(temp);
}
{
let temp = calcAnotherThing();
console.log(temp);
}
}
JavaScripttemp はどちらも「そのブロックの中で完結している変数」なので、
「他の場所から触られない」「紛れ込んだバグも局所的で済む」
というメリットがあります。
「変数の寿命」を短くする発想
ブロックスコープを上手く使う人は、
「変数の寿命をできるだけ短くしよう」と意識しています。
寿命が短い=使う範囲が狭い
使う範囲が狭い=
- 追いかけるべきコードの量が減る
- どこで壊れたかを見つけやすい
ということです。
ここが重要です。
**ブロックスコープを意識して「変数を狭い範囲に閉じ込める」と、
- 変数名の衝突が減る
- どこでどう値が変わるか把握しやすい
結果として、バグの温床を減らせる。**
まとめ:ブロックスコープをどう捉えればいいか
最後に、初心者向けにシンプルにまとめます。
ブロックスコープとは、「{} の中だけ有効な変数の有効範囲」のこと。
let / const で宣言した変数は、その {} の中だけで見える。
外からは見えない。
if の中、for の中、任意の {} など、それぞれが「ミニ世界」。
その中で作った変数は、そのミニ世界だけで使う。
var はブロックスコープがなく、ブロックの外にも変数が漏れるので、予期せぬ上書きやバグの原因になりやすい。
だから今は let / const を使うのが普通。
ブロックスコープを意識して、
「その場限りの変数は、その場(ブロック)の中に閉じ込める」ようにすると、
コードが読みやすく、安全になる。
ここが重要です。
ブロックスコープを一言で言えば、「変数の“見える範囲”を、{} ごとに小さく区切るルール」。
これを味方につけると、「変数が勝手にどこかで書き換わっていた…」という、初学者がハマりがちな泥沼をかなり避けられます。
もしよければ、小さなファイルを作って、
if (true) {
let a = 1;
}
console.log(a); // どうなる?
JavaScriptや、
for (let i = 0; i < 3; i++) {
const msg = "中";
}
console.log(i, msg); // どうなる?
JavaScriptのようなコードを実際に動かしてみてください。
「ここでは見える」「ここでは見えない」を自分の目で確認すると、
ブロックスコープの感覚が一気に身体に入ってきます。
