JavaScript | ES6+ 文法:変数・宣言の進化 – const の仕様

JavaScript
スポンサーリンク

const とは何か

const は ES6 で導入された“ブロックスコープの再代入不可な変数宣言”です。ここが重要です:const は「宣言したブロック内でのみ有効」「同じスコープで再宣言できない」「宣言前は使えない(Temporal Dead Zone)」に加えて、“変数の再代入が禁止”されます。値そのものが不変になるわけではなく、“変数が指す参照が固定される”点を誤解しないでください。

{
  const x = 1;
  // x = 2; // TypeError(再代入不可)
}
JavaScript

スコープと TDZ(宣言前は使えない)

ブロックスコープで安全に閉じる

const は { } で囲んだブロック単位で有効です。if、for、try、switch の中で宣言した const は外から見えません。意図しないスコープ汚染を防ぎます。

if (true) {
  const a = 10;
}
// console.log(a); // ReferenceError(ブロック外)
JavaScript

Temporal Dead Zone(宣言位置までアクセス禁止)

宣言より前の行では参照できません。未初期化のまま使ってしまうバグを“その場で止める”安全機構です。

console.log(n); // ReferenceError(TDZ)
const n = 5;
JavaScript

再代入不可と“参照の不変”(オブジェクトは中身が変えられる)

参照は固定、プロパティは変更可能

const は“変数がどの値(参照)を指すか”を固定します。オブジェクトや配列の“中身”は変更できます(再代入とは別)。

const user = { name: "Alice" };
user.name = "Bob";    // OK(プロパティ変更)
/* user = { name: "Carol" }; */ // NG(再代入)

const list = [1, 2];
list.push(3);         // OK(中身の変更)
/* list = []; */      // NG(再代入)
JavaScript

ここが重要です:値を完全に不変にしたいなら “凍結” を使います。

const user = Object.freeze({ name: "Alice" });
// user.name = "Bob"; // 無効(厳格モードなら例外)
JavaScript

const の初期化と宣言位置(必ず初期値が必要)

初期値なしは不可

const は宣言時に必ず初期化します。後から値を入れる書き方はできません。

/* const x; */           // SyntaxError(初期化必須)
const x = compute();
JavaScript

宣言は“使う直前”が原則

TDZ と読みやすさのため、必要な場所で宣言・初期化します。広いスコープに“未使用の const”を置かない。

function f() {
  const total = calc();  // 使う直前に宣言・初期化
  return total * 2;
}
JavaScript

ループでの const(for-of と相性が良い)

反復ごとに新しい束縛(for-of/for-in)

for-of で const を使うと、各反復で新しい束縛が作られます。ループ内で“変えない値”なら const が最適です。

for (const item of [1, 2, 3]) {
  console.log(item); // 1, 2, 3
  // item = 9; // NG(その反復の束縛は再代入不可)
}
JavaScript

カウンタが必要なら let を選ぶ

数値を増減するような“可変値”は const では書けません。カウンタ・累積は let の責務です。

let sum = 0;
for (const n of [1, 2, 3]) sum += n; // sum は再代入が必要なので let
JavaScript

const と let の使い分け(実務指針)

原則は const、必要なときだけ let

まず const を使い、“再代入が必要”と分かったときに let に切り替えます。不変を増やすほどバグが減り、意図が明確になります。

const items = fetchRows();     // 参照は固定で扱う
let count = 0;                 // 累積は可変なので let
for (const r of items) count += r.value ?? 0;
JavaScript

参照の固定で差分検知・キャッシュが安定

UI状態やメモ化では“参照が変わったか”を === で見ます。非破壊更新+const で参照のライフサイクルを明確にすると、再描画やキャッシュが正しく効きます。

const sorted = rows.toSorted((a,b)=>a.id-b.id); // 新参照
// 以前の rows と === で区別できる
JavaScript

switch の注意点(ブロック化して再宣言エラーを回避)

switch 全体は単一ブロック

case ごとに同名の const を宣言すると再宣言エラーになります。case を { } で囲み、ブロックを分けます。

switch (type) {
  case "A": {
    const msg = "alpha";
    console.log(msg);
    break;
  }
  case "B": {
    const msg = "beta"; // 別ブロックなので OK
    console.log(msg);
    break;
  }
}
JavaScript

例題で理解を固める

const で“意図”を固定してバグを避ける

関数内の設定値や一時計算結果が“変わらない”なら const にしておくと、うっかり再代入のバグを防げます。

function priceWithTax(price) {
  const rate = 0.1;                 // 不変
  const taxed = Math.round(price * (1 + rate));
  return taxed;
}
JavaScript

参照固定+中身変更の現実的なパターン

配列・オブジェクトの“容器”は const で固定し、中身だけ変更する運用は現場でよく使います。

const buffer = [];        // 容器は固定
buffer.push({ id: 1 });   // 中身は追加・更新
buffer.push({ id: 2 });
JavaScript

まとめ

const の核心は「ブロックスコープ」「宣言前不可(TDZ)」「再代入不可(参照固定)」です。オブジェクトや配列の中身は変更可能である点を理解し、完全不変が必要なら Object.freeze を使う。実務では“まず const、必要なら let”を徹底し、宣言は使う直前に、switch は case をブロック化。参照を固定する設計は差分検知やメモ化と相性が良く、初心者でも意図が伝わる安全なコードになります。

タイトルとURLをコピーしました