JavaScript プロトタイプチェーンとメモリレイアウトの仕組み

JavaScript のオブジェクトは、内部に [[Prototype]] という隠しリンクを持ち、プロパティ探索を上位オブジェクトへ委譲する仕組みを備えている。このメカニズムを正確に理解するには、メモリ上でどのように参照が張られるかをイメージすることが不可欠である。

メモリ上の構造

  1. 関数オブジェクト User が生成されると、同時に User.prototype という別オブジェクトが確保される。
  2. new User() でインスタンス u1 が作られると、u1 内部の [[Prototype]] スロットが User.prototype を指す。
  3. プロパティ参照時、インスタンス自身に該当キーがなければ [[Prototype]] を辿って探索が継続される。

動作確認コード

function User() {}

// プロトタイプに共有プロパティを追加
User.prototype.handle = '匿名';
User.prototype.score  = 0;
User.prototype.show   = function () {
  console.log(`${this.handle}: ${this.score}`);
};

const u1 = new User();
u1.show(); // 匿名: 0

// インスタンス固有の値を設定
u1.handle = 'タケシ';
u1.show(); // タケシ: 0

const u2 = new User();
u2.show(); // 匿名: 0  ← プロトタイプ値が参照される

u1.handle = 'タケシ' を実行した瞬間、u1 自身のプロパティとして新しい handle スロットが作成され、以降はプロトタイプの値は隠蔽される(プロパティシャドウイング)。

プロトタイプ診断メソッド

// プロトタイプチェーンに指定オブジェクトが含まれているか
console.log(User.prototype.isPrototypeOf(u1)); // true

// コンストラクタ参照
console.log(u1.constructor === User); // true

// 独自プロパティかどうか
console.log(u1.hasOwnProperty('handle')); // true
console.log(u2.hasOwnProperty('handle')); // false

// プロパティを削除してプロトタイプ値を再露出
delete u1.handle;
console.log(u1.hasOwnProperty('handle')); // false
console.log(u1.handle); // 匿名 ← プロトタイプ値が見える

// in 演算子はチェーン全体を探索
console.log('handle' in u1); // true
console.log('level'  in u1); // false

このように、プロトタイプは単なる「デフォルト値の倉庫」ではなく、メモリ効率を保ちながらメソッドや不変データを共有するための基盤となっている。

タグ: javascript prototype prototype-chain object-model memory-layout

7月13日 22:02 投稿