ES6では変数宣言にlet
とconst
が導入され、従来のvar
に代わって推奨されます。let
とconst
はブロックスコープ({ }
で囲まれた範囲)を持ち、var
のように関数全体やグローバルにまで変数が漏れません。また、let
変数は宣言より前にはアクセスできず、一時的デッドゾーン(TDZ)と呼ばれる状態になります。const
はlet
と同様にブロックスコープですが、再代入ができない点が異なります。一度const
で値を設定すると、同じ変数名で別の値を代入し直すとエラーになります。ただし、const
で宣言したオブジェクトや配列の「中身」は変更可能であることに注意が必要です。
まずはJavaScriptにおけるvar
とlet/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
が発生します。let
とconst
はこのようにブロック単位のスコープを作るため、例えばループ内でlet
を使うと各反復で変数が新しく作られ直し、意図しない値の共有を防げます。
また、const
は再代入不可であるものの、オブジェクトや配列の内容までは不変にするわけではありません。上記例ではuser
オブジェクトのプロパティage
を変更すること自体はエラーになりません(オブジェクトの参照自体は同じままだからです)。しかしuser
に別のオブジェクトを代入し直そうとするとエラーになります。このように、const
は「変数への再代入を禁止する」キーワードだと理解しましょう。実務では、「再代入しない変数は全てconst
を使い、そうでなければlet
を使う」というコーディングスタイルが一般的です。