【Javascript】 スコープとブロック – プログラミング入門

スコープとは、宣言した変数などが利用できる範囲のことです。これをうまく活用すると、思わぬバグを防いだり、変数名の重複で悩むことが減少します。

構造

スコープは、通常は波括弧で囲まれたブロックという領域に発生します。ifで実行する中身や、forで実行する中身というのは、実はブロック(コードブロック)です。

下のコードはスコープの挙動の例です。

let x = 0;
if (x == 0) {
    // もちろんxは使える
    console.log(x);

    let y = 10;

    // もちろんyも使える
    console.log(y);
}

// yはここでは使えない!
// console.log(y);

// xは使える
console.log(x);

さて、ここでそれぞれの変数の状態を見てみましょう。

スコープ

変数は、宣言されてから元いたブロックが終わるまでしか利用できません。

範囲を制限することは一見使いづらく見えますが、コードを書き慣れてくると、変数管理の楽さ、コードの見晴らしの向上など、多くの面で利点を感じることができます。結果的に、バグの低減や素早い解決にも繋がります。

他にも、意図的に制限を加えることで、可読性の向上やバグ防止に役立つことが数多くあります。基本的に、必要ない操作はできないようにする、というのが実際にものを作る上でのプログラミングの鉄則です。

しかし, constの説明は、この時点ではまだ早すぎるので、letで進めています。

実は、既に活用している場面があります。for文です。

for文ではfor (let i = 0; ...)と書きましたが、このiはforの括弧内と実行する中身でしか使用できない変数です。

ブロックを重ねた時の挙動

ブロックが重なっているときのスコープの挙動を見てみましょう。

let x = 0;
if (x == 0) {
    let y = 10;

    if (y == 10) {
        let z = 0;
    } // zはここまで

} // yはここまで

// xはまだ使える

となります。yを見ると、内側ブロックが終わってもまだ使うことができます。yが宣言されたブロックはif (x == 0)の直後にあるブロックなので、yが宣言されてからそのブロックの終わりまで利用できます。

別々のブロックで同じ変数名を使う

ブロックが異なれば同じ変数名でも大丈夫です。

let x = 0;
if (x == 0) {
    let y = 10;
    console.log(y);
}
if (x == 0) {
    let y = 500;
    console.log(y);
}
10
500

このように、yが2回宣言されています。変数名は重複できないものですが、それはプログラムがどちらを使ったらよいかわからなくなるためです。宣言したブロックが異なる場合などではプログラム側で区別できるので、同じ変数名が利用できます。

この例の場合、1回目のyは、1回目のifが終わると同時に使えなくなる、つまり再び使える名前として開放されるということです。

ブロックがネストされているときの変数名

少し発展的な内容です。

ネストとは、ブロックの中にブロックがある状態のことです。例えば。

if (1) {
    if (2) {
        /*...*/
    }
}

だと、if文がネストされている、という状態です。

ブロックがネストされている場合、変数名はかぶって大丈夫ですが、より狭いスコープの方だけが利用されます。

let x = 0;
if (x == 0) {
    let x = 10;
    if (x == 10) {
        console.log("実行される");
    }
}

この場合、x == 10の判定をするときは、スコープが狭い変数であるlet x = 10;にあるxが使われます。そのため、if文は条件を満たします。

とはいえ、こういったものはバグの温床になるため、極力避けましょう。人の目で見たときに、より狭いスコープの宣言を見逃したり、スコープを勘違いしたりするためです。

スコープの単位

スコープはブロック以外でも発生します。例えば、ファイル単位です。

let x = 0; // 宣言したあとなら、このファイル内のどこでも使える

function hoge(arg) { // 変数argは、この関数のブロック内でのみ利用できる
    let y = 0; // 宣言したあとなら、このブロック内のどこでも使える

    for (let i = 0; i < 10; i++) { // iはこのforの括弧内、またはブロック内で使える
        let z = 0; // 宣言したあとなら、このブロック内のどこでも使える。 forの条件式などには使えない
    }

    var hoge = 0; // varなら、宣言前でもどこでも使える (危険なため、普通は使わない)
}

上の例だと、変数xはそのファイル内であればどこでも使えます。 (流石に宣言前では使えないので、宣言後です。)

ブロックとスコープの違い

似ている言葉が出てきたので、ここで一旦整理しましょう。

ブロック
波括弧で囲ったプログラムのまとまり
スコープ
宣言した変数が使える範囲。宣言してからブロックの終わりまで使える

です。2つの違いをしっかり把握しましょう!

まとめ

スコープとブロックを紹介しました。スコープは変数などが使える範囲を指し、ブロックは波括弧で囲んだ人まとまりのコードです。

スコープは、ある変数が宣言された後から、宣言場所のブロックが終わるまでです。

質が高いコードを書くために、できるだけ狭くできるように意識していきましょう。

変数など、と書いてあるとおり、変数以外の要素でもスコープが存在します。クラスやクロージャなどを考えるときに非常に重要です。

scope thumb

役に立ったらシェアしよう!