1
0

JavaScript: プロトタイプチェーンにおけるプロパティ探索の順序

Last updated at Posted at 2024-08-28

アジェンダ

プロトタイプチェーンにおけるプロパティ探索の順序について簡単にまとめます。

プロパティ探索の順序

  1. オブジェクト自身のプロパティ:
    まず、オブジェクト自身が持っているプロパティが参照されます。もしそのプロパティが存在する場合は、その値が返されます。

  2. オブジェクトのプロトタイプ (__proto__):
    2オブジェクト自身に該当するプロパティがない場合、そのオブジェクトのプロトタイプオブジェクトが参照されます。このプロトタイプオブジェクトもまたオブジェクトであり、同じ手順でプロパティが探されます。

  3. プロトタイプチェーンの遡り:
    プロトタイプオブジェクトにも該当するプロパティがない場合、そのプロトタイプオブジェクトのプロトタイプ(つまり、プロトタイプのプロトタイプ)が参照されます。これが繰り返され、チェーンを辿っていきます。

  4. 最上位の Object.prototype:
    最終的に、すべてのオブジェクトは Object.prototype に辿り着きます。Object.prototype には標準的なJavaScriptのオブジェクトが共通で持つメソッドやプロパティ(toString()hasOwnProperty() など)が定義されています。

  5. null:
    プロトタイプチェーンの最上位は null で、null に達するとそれ以上プロトタイプチェーンを遡ることはできません。もし参照するプロパティがチェーン内のどのオブジェクトにも存在しない場合は、undefined が返されます。

このように、プロトタイプチェーンはオブジェクト自身から始まり、順次プロトタイプを遡りながら該当するプロパティを探していく仕組みです。

実例:

先ほどの1から5の流れを実感するために、実例として以下の様なコードがあるとします。
このコードでは、Person コンストラクタ関数を定義し、そのプロトタイプに greet メソッドを追加しています。johnPerson のインスタンスです。

function Person(name) {
    this.name = name;
}

Person.prototype.greet = function() {
    return `Hello, my name is ${this.name}`;
};

const john = new Person('John');

では、上記john オブジェクトを活用してプロパティやメソッドがどのように参照されるかを確認していきます。

1. オブジェクト自身のプロパティ

console.log(john.name); // 'John'

ここでは、john オブジェクトに直接 name プロパティが存在するため、John が返されます。

2. オブジェクトのプロトタイプ (__proto__)

console.log(john.greet()); // 'Hello, my name is John'

john オブジェクトには greet プロパティが存在しないため、Person.prototype にある greet メソッドが参照され、実行されます。

3. プロトタイプチェーンの遡り

console.log(john.toString()); // '[object Object]'

toString メソッドは john オブジェクトにも Person.prototype にも存在しませんが、Person.prototype のプロトタイプである Object.prototype に定義されています。したがって、Object.prototype.toString メソッドが実行されます。

4. 最上位の Object.prototype

console.log(john.hasOwnProperty('name')); // true

hasOwnProperty メソッドも Object.prototype に存在します。john オブジェクトには直接存在しませんが、プロトタイプチェーンを遡って Object.prototype.hasOwnProperty メソッドが呼び出されます。

5. null

プロトタイプチェーンの最後は null に到達します。もし参照しているプロパティが Object.prototype にも存在しなければ、undefined が返されます。

console.log(john.nonExistentProperty); // undefined

johnオブジェクトを展開

john オブジェクトを展開すると、以下のような形で表示されます。
これはオブジェクトの各プロパティとそのプロトタイプチェーンの構造を示します。

{
  name: 'John',
  __proto__: {
    greet: function() { return `Hello, my name is ${this.name}`; },
    __proto__: {
      // Object.prototype のプロパティとメソッド
      constructor: function Object() { ... },
      hasOwnProperty: function hasOwnProperty() { ... },
      isPrototypeOf: function isPrototypeOf() { ... },
      propertyIsEnumerable: function propertyIsEnumerable() { ... },
      toString: function toString() { ... },
      valueOf: function valueOf() { ... },
      // さらに他の Object.prototype のプロパティ
      __proto__: null
    }
  }
}
  1. name: 'John':

    • john オブジェクトに直接定義されているプロパティです。
  2. __proto__:

    • john オブジェクトのプロトタイプ (Person.prototype) への参照です。ここに greet メソッドが定義されています。
  3. Person.prototype__proto__:

    • Person.prototype のプロトタイプは Object.prototype です。ここには constructortoString などの標準的なJavaScriptのオブジェクトに共通のプロパティやメソッドが定義されています。
  4. Object.prototype__proto__:

    • Object.prototype のプロトタイプは null です。これはプロトタイプチェーンの最上位であり、これ以上遡ることはありません。

まとめ

プロパティが見つかるまでプロトタイプチェーンを順番に遡ることで、JavaScriptは適切なプロパティやメソッドを見つけ出します。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0