1. 基本ルール(要点)
const は「再代入できない束縛(binding)」を作るキーワードです。宣言と同時に必ず初期化が必要で、あとから別の値を代入するとエラーになります。
const a = 10;
a = 20; // TypeError: Assignment to constant variable.
const b; // SyntaxError: Missing initializer in const declaration
JavaScript
2. スコープ(ブロックスコープ)とTDZ(Temporal Dead Zone)
const は let と同じくブロックスコープ({ ... } 内だけ有効)。関数スコープの var とは違います。
- 宣言より前にアクセスすると TDZ(Temporal Dead Zone) により参照エラーになります。つまり「見た目はホイストされているが使えない」状態です。
{
console.log(x); // ReferenceError (TDZ)
const x = 1;
}
JavaScript
3. const は「不変(immutable)」ではない — 参照の不変性
- 重要な誤解:
const は「値そのものを不変にする」わけではなく、変数名が参照する先(アドレス)を変えられないだけです。プリミティブ(数値・文字列など)では再代入できない=事実上不変に見えますが、参照型(オブジェクト・配列・関数)は中身の変更はできる点に注意。
const arr = [1,2];
arr.push(3); // OK -> arr は [1,2,3]
arr = [4,5]; // TypeError: Assignment to constant variable.
const obj = { a: 1 };
obj.a = 2; // OK -> obj.a は 2
obj = {}; // TypeError
JavaScript
4) オブジェクト/配列を本当に不変にしたいとき
Object.freeze(obj) を使うと そのオブジェクトのプロパティを「浅く」凍結(新しいプロパティ追加や既存プロパティの書き換えが不可)できます。ただしネストされたオブジェクトは深くは凍結されません(深い不変化は別実装が必要)。
const p = { name: "A", nested: { v: 1 } };
Object.freeze(p);
p.name = "B"; // 失敗(strict mode では TypeError、非 strict では無視)
p.nested.v = 2; // これは変更できてしまう(浅い freeze)
JavaScript
- 実務では「浅い freeze で十分か」「完全不変が必要か」を判断して、必要なら再帰的に freeze するユーティリティや不変ライブラリ(immer / Immutable.js 等)を使います。
5. 宣言・再宣言・再代入の扱い(細かいルール)
- 同じスコープ内で
const を再宣言(同名)することはできません(SyntaxError)。
- トップレベルで
const 宣言した変数は、スクリプトのグローバルオブジェクト(globalThis)のプロパティにはならない、という挙動があります(var とは異なる)。
6. 実用的な使い方(ベストプラクティス)
- まず
const をデフォルトで使い、変える必要が出たら let にする(変更しないことを前提に書くとバグが減る)。
- 定数的な値(設定値、固定の配列/オブジェクト参照)には
const を使う。必要であれば Object.freeze() で凍結する。
for (const x of arr) のようにループで使うときは「各イテレーションで新しい束縛が作られる」ため問題なく使えます(ただし束縛自体の再代入はできない)。
7. よくある落とし穴(まとめ)
- 「
const = 不変」だと誤解してオブジェクトの中身を書き換えられることに気づかない。→ 意図的な不変化が必要なら Object.freeze や不変データ手法を検討。
- TDZ による ReferenceError。宣言より前に使わないこと。
- グローバルで
const を使っても globalThis のプロパティにはならない挙動(var と違う)。