第1章: 変数宣言 (let/const) とスコープ

第1章: 変数宣言 (let/const) とスコープ

概要

ES6では変数宣言にletconstが導入され、従来のvarに代わって推奨されます。letconstはブロックスコープ({ }で囲まれた範囲)を持ち、varのように関数全体やグローバルにまで変数が漏れません。また、let変数は宣言より前にはアクセスできず、一時的デッドゾーン(TDZ)と呼ばれる状態になります。constletと同様にブロックスコープですが、再代入ができない点が異なります。一度constで値を設定すると、同じ変数名で別の値を代入し直すとエラーになります。ただし、constで宣言したオブジェクトや配列の「中身」は変更可能であることに注意が必要です。

コードと解説

まずはJavaScriptにおけるvarlet/constの挙動の違いを確認しましょう。

// varとletのスコープの違い
function scopeTest() {
    if (true) {
        var x = 1;
        let y = 2;
    }
    console.log(x); // 1 (varで宣言したxは関数スコープなのでここでも参照可能)
    console.log(y); // ReferenceError: y is not defined (letで宣言したyはブロックスコープなのでブロック外では未定義)
}
scopeTest();

// constの再代入禁止
const PI = 3.14;
PI = 3.15; // エラー: const変数には再代入できない

// constで宣言したオブジェクトの中身は変更可能
const user = { name: "Alice", age: 25 };
user.age = 26;       // プロパティの変更は可能
user = { name: "Bob", age: 30 }; // エラー: user自体を別のオブジェクトに再割り当てすることはできない

解説: 上記のコードでは、varで宣言したxは関数scopeTest内であればブロックを越えて参照できます。一方letで宣言したyはそのブロック内でのみ有効で、ブロックの外に出ると存在しなくなるためReferenceErrorが発生します。letconstはこのようにブロック単位のスコープを作るため、例えばループ内でletを使うと各反復で変数が新しく作られ直し、意図しない値の共有を防げます。

また、constは再代入不可であるものの、オブジェクトや配列の内容までは不変にするわけではありません。上記例ではuserオブジェクトのプロパティageを変更すること自体はエラーになりません(オブジェクトの参照自体は同じままだからです)。しかしuserに別のオブジェクトを代入し直そうとするとエラーになります。このように、constは「変数への再代入を禁止する」キーワードだと理解しましょう。実務では、「再代入しない変数は全てconstを使い、そうでなければletを使う」というコーディングスタイルが一般的です。

目次に戻る