【入門編】constによる参照の固定と「不変性」の限界:Object.freezeと組み合わせた堅牢な設計 – JavaScriptコア文法・モダン言語仕様と変数・関数解析バイブル

こんにちは!JavaScriptのコアな仕組みからモダンなフロントエンド開発まで、日夜コードと向き合っているフロントエンド・アーキテクトの私です。

今回は、JavaScriptの変数宣言において誰もが一度は誤解しがちな「`const`の本当の意味」と、オブジェクトを完全に守り抜くための「`Object.freeze`との組み合わせによる堅牢な設計パターン」について、V8エンジンのメモリ構造の裏側まで少しだけ覗きながら、優しく、そして深く解説していきますね。

ここをクリアすれば、あなたの書くコードの安全性は劇的に跳ね上がります。一緒にバッチリマスターしていきましょう!

—

1. `const`は「値の不変(イミュータブル)」ではなく「再代入の禁止」である

JavaScriptを学び始めて最初に覚える変数宣言といえば、`const`ですよね。「定数を宣言するキーワード」として教わった方が多いはずです。

例えば、こんなコードを書いたとします。

const taxRate = 0.1;
// taxRate = 0.08; // ❌ エラー!再代入はできません

これはバッチリ動きますし、意図しない再代入を防いでくれる最高の機能です。では、次のコードはどうでしょうか?

const user = {
name: ‘Taro’,
age: 25
};

// プロパティの書き換えは…?
user.age = 26; // ⚠️ えっ、エラーにならないの!?
console.log(user.age); // 出力: 26

「あれ?`const`を使っているのに、オブジェクトの中身が変わっちゃったぞ?」と戸惑いませんでしたか?そうなんです。これが、初学者が一番最初にハマるJavaScriptの罠であり、本質を理解するための重要な分岐点になります。

メモリの視点から見る `const` の正体

JavaScriptのエンジン(V8など)の頭の中を少し覗いてみましょう。

変数にオブジェクトを代入したとき、メモリ(ヒープ領域)の空間には「オブジェクトの実体」がポツンと作られます。そして、変数(`user`)が持っているのは、その実体が「どこにありますよ」という「メモリアドレス(参照)」でしかありません。

`const`が固めているのは、この「変数に格納されたメモリアドレスの箱」です。

[ const user ] ──(参照を固定!変更不可)──> { name: ‘Taro’, age: 25 }
│
(中身の書き換えは自由!)
↓
{ name: ‘Taro’, age: 26 }

つまり、`const`は「別のオブジェクトの住所に書き換えること(再代入)」は厳禁しますが、「住所の先にある家の中の家具を勝手に模様替えすること(プロパティの変更)」までは止めてくれないのです。

—

2. オブジェクトを完全に凍結する:`Object.freeze()` の登場

「じゃあ、オブジェクトの中身すら一切書き換えられたくない(完全な不変性にしたい)場合はどうすればいいの?」という疑問が湧きますよね。

そこで登場するのが、JavaScriptが標準で持っている魔術、`Object.freeze()` です。

`Object.freeze()`をオブジェクトに通すと、そのオブジェクトは「凍結(フリーズ)」され、プロパティの追加、削除、そして値の変更が一切できなくなります。

実際のコードでその挙動を見てみましょう。

// const と Object.freeze を組み合わせる
const immutableUser = Object.freeze({
name: ‘Hanako’,
age: 22
});

// 1. プロパティの値を変更しようとしてみる
immutableUser.age = 30;
console.log(immutableUser.age); // 出力: 22 (変わっていない!)

// 2. 新しいプロパティを追加しようとしてみる
immutableUser.gender = ‘female’;
console.log(immutableUser.gender); // 出力: undefined (追加もできない!)

// 3. プロパティを削除しようとしてみる
delete immutableUser.name;
console.log(immutableUser.name); // 出力: ‘Hanako’ (削除もできない!)

すごいですね!`const`で「住所の変更」を封じ、`Object.freeze()`で「家の中の改築」を封じる。この2つをタッグを組ませることで、初めて「真に堅牢な不変オブジェクト(イミュータブル・データ)」が完成するのです。

—

3. 実務で気をつけるべき「浅い凍結(Shallow Freeze)」の罠

さて、ここでワンランク上のプログラミング知見をお伝えしておきます。実は、`Object.freeze()`には「1階層目しか凍結しない(浅い凍結)」という重要な仕様上の限界があります。

例えば、オブジェクトの中に「ネスト(入れ子)された別のオブジェクト」がある場合を考えてみましょう。

const company = Object.freeze({
name: ‘Tech Corp’,
address: {
city: ‘Tokyo’,
street: ‘Shibuya’
}
});

// 1階層目は凍結されているので変更できない
company.name = ‘Startup Inc’; // 無視される(strictモードではエラー)

// しかし! 2階層目のオブジェクトは…?
company.address.city = ‘Osaka’;
console.log(company.address.city); // 出力: Osaka 😱 変わってしまった!

なぜこうなるのでしょうか?
`Object.freeze(company)` は、`company` が直接持っている `name` や `address` というプロパティの「参照」を凍結しますが、`address` が指し示す「別のオブジェクトの内部」までは自動的に巡回して凍結してくれないからです。

完全な不変性を手に入れるための「ディープ・フリーズ(深層凍結)」

実務で本当に安全なアプリケーション設計(例えばReduxのステート管理や設定ファイルの保持など)を行うときは、ネストしたオブジェクトも含めて再帰的に凍結する「ディープ・フリーズ関数」を自前で用意するのがプロの技です。

以下に、実戦でそのまま使えるユーティリティコードを置いておきますね。

/

  • オブジェクトを再帰的に完全凍結する関数
  • @param {Object} obj 凍結したいターゲットオブジェクト
  • @returns {Object} 凍結されたオブジェクト

/
function deepFreeze(obj) {
// オブジェクトが持つすべてのプロパティ名を取得
const propNames = Object.getOwnPropertyNames(obj);

// プロパティが指し示す先がオブジェクトであれば、再帰的にfreezeする
for (const name of propNames) {
const value = obj[name];

if (value && (typeof value === ‘object’ || typeof value === ‘function’)) {
deepFreeze(value);
}
}

return Object.freeze(obj);
}

// — 使用例 —
const secureConfig = deepFreeze({
appName: ‘SuperApp’,
db: {
host: ‘localhost’,
port: 5432
}
});

// ネストされた値も変更できなくなる!
// secureConfig.db.port = 3306; // 失敗する(strictモードならTypeError)

このように、データの構造が深くなっても「どこを触っても絶対に壊れない(変異しない)」という保証をコードに持たせることで、バグの温床を根絶やしにすることができます。

—

まとめ:堅牢な設計のファーストステップ

今回は、`const`の限界と、それを補う`Object.freeze()`の組み合わせについて解説しました。

  • `const` は変数の「再代入」を防ぐが、オブジェクトの「プロパティの書き換え」までは防げない。
  • `Object.freeze()` を組み合わせることで、オブジェクトの改変を食い止めることができる。
  • ただし、通常の `freeze` は「浅い凍結」なので、ネストしたオブジェクトには再帰的な処理(Deep Freeze)が必要になる。

データを「イミュータブル(不変)」に保つという考え方は、予期せぬバグを防ぎ、コードの予測可能性を劇的に高めてくれるモダン開発の必須教養です。ぜひ、今日のコードから `const + Object.freeze` のコンビネーションを意識して取り入れてみてくださいね。

ここをクリアしたあなたなら、JavaScriptの変数とメモリの挙動はもうバッチリマスターできていますよ!自信を持って次のステップへ進んでいきましょう。

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