JavaScript | ES6+ 文法:オブジェクト拡張 – Object.getPrototypeOf

JavaScript JavaScript
スポンサーリンク

Object.getPrototypeOf とは何か

Object.getPrototypeOf は、あるオブジェクトの「プロトタイプ(親オブジェクト)」を取り出すためのメソッドです。
プロトタイプとは、そのオブジェクトが「継承している元(テンプレートのようなもの)」だと思ってください。

const obj = {};
const proto = Object.getPrototypeOf(obj);

console.log(proto);                // 何かしらのオブジェクト
console.log(proto === Object.prototype); // true であることが多い
JavaScript

ここが重要です。
JavaScript のオブジェクトは、ほとんどが「どこかのオブジェクトを親(プロトタイプ)として持っていて、その親からプロパティやメソッドを“借りて使っている”」。
Object.getPrototypeOf は、その「親は誰?」を教えてくれる関数です。


プロトタイプってそもそも何?を直感的に理解する

JavaScript では、オブジェクトが「別のオブジェクトを親として持ち、その親のプロパティやメソッドを自分のもののように使う」仕組みになっています。これを「プロトタイプチェーン」と呼びます。

例えば、空オブジェクト {} にも toString() メソッドがありますが、自分で定義していませんよね。
これは、{} のプロトタイプである Object.prototypetoString を持っているからです。

const obj = {};

console.log(obj.toString); // function toString() { ... } など
JavaScript

このとき、

Object.getPrototypeOf(obj) === Object.prototype // たいてい true
JavaScript

となっていて、「obj の親は Object.prototype です」という関係になっています。

ここが重要です。
自分が定義していないメソッドを使えるのは、「プロトタイプ(親オブジェクト)から借りている」から。
Object.getPrototypeOf は、その「借り元」が誰かを確認するための道具です。


Object.getPrototypeOf の基本的な使い方

素朴なオブジェクトのプロトタイプを調べる

const obj = { a: 1 };
const proto = Object.getPrototypeOf(obj);

console.log(proto);                    // 何かしらのオブジェクト
console.log(proto === Object.prototype); // true(通常はこうなる)
JavaScript

{}{ a: 1 } のような「リテラルで作ったオブジェクト」の多くは、Object.prototype を親に持ちます。
Object.prototype は、toString, hasOwnProperty, valueOf などの基本メソッドを持っている元締めのような存在です。

Object.create と組み合わせてみる

Object.create で「プロトタイプを指定してオブジェクトを作る」と、そのプロトタイプがそのまま Object.getPrototypeOf で取れます。

const parent = { x: 1 };
const child = Object.create(parent);

console.log(Object.getPrototypeOf(child) === parent); // true
console.log(child.x);  // 1(自分にはないけど、親から借りている)
JavaScript

ここが重要です。
Object.create(parent) で「親が parent のオブジェクト」ができる。
Object.getPrototypeOf(child) は、その「設定された親」がそのまま返ってくる。


クラスやコンストラクタ関数との関係を見てみる

コンストラクタ関数で作ったインスタンスの場合

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

const p = new Person("Alice");

console.log(Object.getPrototypeOf(p) === Person.prototype); // true
JavaScript

new Person(...) で作られたオブジェクトのプロトタイプは、Person.prototype になります。
つまり、「p の親は Person.prototype」という関係です。

Person.prototype にメソッドを定義すると、p からも使えるようになります。

Person.prototype.greet = function () {
  console.log("Hello, " + this.name);
};

p.greet(); // "Hello, Alice"
JavaScript

このとき、

Object.getPrototypeOf(p) === Person.prototype // true
JavaScript

で、「greet を持っている親」が誰かを確認できる、というわけです。

class 構文の場合も同じ考え方

ES6 の class を使っても、裏側では同じようにプロトタイプが使われています。

class User {
  constructor(name) {
    this.name = name;
  }
  greet() {
    console.log(`Hi, ${this.name}`);
  }
}

const u = new User("Bob");

console.log(Object.getPrototypeOf(u) === User.prototype); // true
u.greet(); // "Hi, Bob"
JavaScript

ここが重要です。
class を使っていても、「インスタンスの親(プロトタイプ)はクラス名.prototype」というルールは同じ。
Object.getPrototypeOf は、クラスのインスタンスが「どのクラス(あるいはどのプロトタイプ)から来ているか」を調べるのにも使えます。


proto との違いと、なぜ Object.getPrototypeOf を使うのか

多くの環境では、オブジェクトに obj.__proto__ というプロパティがあり、これでもプロトタイプを取れます。

const obj = {};
console.log(obj.__proto__ === Object.prototype); // true になりがち
JavaScript

ただし、__proto__ はもともと「非標準の歴史的プロパティ」であり、仕様としては「なるべく使わないでね」的な扱いをされています。
Object.getPrototypeOf(obj) は、同じことをする「正式な標準メソッド」です。

ここが重要です。
__proto__ は動くけれど、モダンな書き方としては Object.getPrototypeOf(obj) を使う。
「プロトタイプを調べたいときの正しいやり方」として覚えておくと、他人のコードを読むときも迷いません。


どんなときに使うのか(実務寄りのイメージ)

初心者向けの普通のアプリコードでは、Object.getPrototypeOf を頻繁に書くことはあまりありません。
それでも理解しておくと得する場面を挙げてみます。

一つは「デバッグ・調査」です。
「このオブジェクトって何者? どこから来ている?」を知りたいときに、プロトタイプを見ると正体が分かったりします。

function debugProto(obj) {
  const proto = Object.getPrototypeOf(obj);
  console.log("prototype:", proto);
}

debugProto([]);     // Array.prototype が見える
debugProto({});     // Object.prototype が見える
debugProto(new Map()); // Map.prototype が見える
JavaScript

ライブラリの内部やフレームワークで、

「このインスタンスはどのクラス(コンストラクタ)から来ているのか」を判断するために
Object.getPrototypeOf(obj) === SomeClass.prototype のようなチェックを使うこともあります。

もう一つは、「自分でシンプルな継承っぽい仕組みを書く」ときです。
Object.createObject.getPrototypeOf を組み合わせて、「親子関係」がきちんと繋がっているか確認できます。


プロトタイプチェーンを少しだけ覗いてみる

Object.getPrototypeOf を何度か使うことで、「プロトタイプチェーン」を辿ることもできます。

const obj = {};
const p1 = Object.getPrototypeOf(obj);         // たぶん Object.prototype
const p2 = Object.getPrototypeOf(p1);          // たぶん null

console.log(p1); // Object.prototype 相当
console.log(p2); // null(これ以上親がいない)
JavaScript

Object.prototype のさらに上は null です。
ここでチェーンが終わる、というのが JavaScript のオブジェクトの基本構造です。

配列の場合も同様に辿れます。

const arr = [];
const pArr = Object.getPrototypeOf(arr);    // Array.prototype
const pObj = Object.getPrototypeOf(pArr);   // Object.prototype
const pNull = Object.getPrototypeOf(pObj);  // null
JavaScript

ここが重要です。
あらゆるオブジェクトが、「自分 → 何らかのプロトタイプ → Object.prototype → null」というような鎖の上にいる。
Object.getPrototypeOf は、その鎖を一段ずつ上に辿るためのメソッドです。


例題で理解を固める

// 1) リテラルオブジェクトのプロトタイプ
const obj = { a: 1 };
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true

// 2) Object.create で作ったオブジェクト
const parent = { x: 1 };
const child = Object.create(parent);
console.log(Object.getPrototypeOf(child) === parent); // true

// 3) コンストラクタ関数のインスタンス
function Person(name) {
  this.name = name;
}
const p = new Person("Alice");
console.log(Object.getPrototypeOf(p) === Person.prototype); // true

// 4) class のインスタンス
class User {
  constructor(name) {
    this.name = name;
  }
}
const u = new User("Bob");
console.log(Object.getPrototypeOf(u) === User.prototype); // true

// 5) 配列のプロトタイプチェーン
const arr = [1, 2, 3];
console.log(Object.getPrototypeOf(arr) === Array.prototype);        // true
console.log(Object.getPrototypeOf(Array.prototype) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype));               // null
JavaScript

まとめ

Object.getPrototypeOf の核心は、
「このオブジェクトの“親(プロトタイプ)”は誰か?」を教えてくれる関数である、という点です。

プロトタイプは、
「自分で持っていないプロパティやメソッドを、“どこから借りているか”を決める仕組み」です。
Object.getPrototypeOf を理解すると、

オブジェクトリテラル
コンストラクタ関数+prototype
class
Array や Map などのビルトインオブジェクト

これらが、すべて同じ「プロトタイプチェーン」という仕組みの上で動いていることが見えてきます。

初心者のうちは、
「プロトタイプ = 親オブジェクト」「Object.getPrototypeOf(obj) = 親を教えてくれる関数」
という直感だけしっかり掴んでおけば十分です。そこから少しずつ、クラスや継承の仕組みを紐づけていくと理解が深まります。

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