Object.getPrototypeOf(obj) は obj.constructor.prototype と同義か？

# はじめに

[Effective JavaScript](https://www.amazon.co.jp/dp/B00EESW7JQ) を読み返していると、項目 31 で覚えておくべき事項として以下が紹介されていました。

> 非標準の \_\_proto\_\_ プロパティよりも、標準に準拠した Object.getPrototypeOf が好ましい。

なるほど [Object.getPrototypeOf()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf) があるのか :innocent:

ここで「`Object.getPrototypeOf()` は `obj.constructor.prototype` では代用できないだろうか」という疑問が湧きました。そこで調べてみると、StackOverflow に [is Object.getPrototypeOf() same as Object.constructor.prototype in Javascript?](http://stackoverflow.com/questions/8024879/is-object-getprototypeof-same-as-object-constructor-prototype-in-javascript) というまさしく求めていた記事を発見しました。そこで、その記事の内容を整理して共有したいと思います。

## 追記 (2016/11/16 (水))

\_\_proto\_\_ プロパティは標準化されていると @mysticatea 様にご指摘頂きました。ありがとうございます :bow:

確かに MDN の [Object.prototype.\_\_proto\_\_](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)  にも

> \_\_proto\_\_ プロパティはECMAScript第６版言語仕様で標準化されました。そして、将来にサポートされます。

と言及されていますね。ただし、パフォーマンス上の観点から、やはり使用は推奨されていないようです。

# 概要

先にタイトルの答えを発表すると **NO** :no_good: です。

例えば [Object.create()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/create) で引数に `null` を渡してオブジェクトを生成したとします。これは `prototype` を `null` としてオブジェクトを生成するということです。この場合 `obj.constructor` は `undefined` となるため `obj.constructor.prototype` を取得することはできません。

```js
let obj1 = Object.create(null);

obj1.constructor; // undefined
```

一方 `Object.getPrototypeOf()` メソッドは `null` を返します。

```js
Object.getPrototypeOf(obj1); // null
```

`prototype` が `null` の場合でも利用できるのは便利ですね。

対して、一般的なオブジェクト (`prototype` として `Object.prototype` を持つオブジェクト) の場合は一致します。

```js
let obj2 = {};

Object.getPrototypeOf(obj2); // Object.prototype
obj.constructor.prototype; // Object.prototype

Object.getPrototypeOf(obj2) === obj.constructor.prototype; // true
```

なお `Object.create(null)` で生成したオブジェクトについても、手動で `prototype` に `Object.prototype` 設定すれば、一般的なオブジェクトの場合と同じ挙動になります。

```js
let obj3 = Object.create(null);
Object.setPrototypeOf(obj3, Object.prototype);

obj3.constructor.prototype; // Object.prototype
Object.getPrototypeOf(obj3); // Object.prototype

obj3.constructor.prototype === Object.getPrototypeOf(obj3); // true
```

なお [Object.setPrototypeOf()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) は ECMAScript 6 のメソッドです。

## 追記 (2016/11/16 (水))

@mysticatea 様より

> obj.constructorは書き換え可能なプロパティであるため、本当にobjのコンストラクタを指しているとは限りません。

とのご指摘を頂きました。ありがとうございます :bow:

確かに、このことも `Object.getPrototypeOf(obj)` と `obj.constructor.prototype` の大きな差異ですね。

```js
function PseudoObject() {};
PseudoObject.prototype = {};

let obj4 = new PseudoObject();

obj4.constructor.prototype; // Object.prototype
Object.getPrototypeOf(obj4); // PseudoObject.prototype

obj4.constructor.prototype === Object.getPrototypeOf(obj4); // false
```

# 参考

* <i class="fa fa-stack-overflow fa-fw"></i> StackOverflow
    * [is Object.getPrototypeOf() same as Object.constructor.prototype in Javascript?](http://stackoverflow.com/questions/8024879/is-object-getprototypeof-same-as-object-constructor-prototype-in-javascript)
* <i class="fa fa-firefox fa-fw"></i> MDN 
    * [Object.prototype.\_\_proto\_\_](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/proto) 
    * [Object.prototype](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype)
    * [Object.create()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
    * [Object.getPrototypeOf()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf)
    * [Object.setPrototypeOf()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf)