.prototype.__proto__

__proto__プロパティは、使用しないでください。 オブジェクトの[[prototpye]]を調べるために__proto__のgetterを使用する代わりに、 Object.getPrototypeOfを使用するべきです。

オブジェクトの[[Prototype]]の変更は、例えそれが出来たとしても、 モダンなJavaScript実装では非常に遅く、それに続く処理速度低下が避けられないことから、 強く非推奨とされています。 __proto__のsetterの代わりとして、 ES6で提供されるObject.setPrototypeOfを使用するのが良いでしょう。

プロパティへのアクセサー(getter、setter関数)で、 オブジェクトの内部[[Prototype]](オブジェクトまたはnull)へのアクセスを通して公開されます。

文法

var proto = obj.__proto__;

説明

__proto__のgetter関数は、オブジェクトの内部[[Prototype]]の値を公開します。 オブジェクトのリテラルを使用して作成されたオブジェクトであれば、 この値はObject.prototypeになります。 配列のリテラルを使用して作成されたオブジェクトであれば、 この値はArray.prototypeになります。 関数であれば、この値はFunction.prototypeになります。

new funを使用して作成されたオブジェクトであり、 funがJavaScriptによって提供される組み込みコンストラクタ関数(Array、 Boolean、 Date、 Number、 Object, String等や、 今後JavaScriptに追加される新しいコンストラクタも含め)のいずれかであれば、 この値はfun.prototypeになります。

new funを使用して作成されたオブジェクトであり、 funがスクリプトで定義されたものであれば、 この値はnew funが評価された際のfun.prototypeの値になります。 (新しい値がfun.prototypeに割り当てられる場合、 それ以前に作成されているfunインスタンスは、その以前の値を[[Prototype]]として持ち続け、 その後のnew funによる処理では、新しく割り当てられた値が[[Prototype]]として使用されます。)

オブジェクトの[[Prototype]]へアクセスするために、 Object.getPrototypeOf関数が用意されています。 __proto__と、そのgetter関数は非推奨であり、使用すべきではありません。

__proto__のsetterは、オブジェクトの[[Prototype]]を変更することが可能です。 そのオブジェクトはObject.isExtensibleに従って拡張可能でなければいけません。 もしそうで無ければ、TypeErrorがスローされます。 提供される値は、オブジェクトまたはnullで無ければいけません。 その他の値が提供された場合は、何も行われません。

モダンなJavaScriptエンジンによるプロパティへのアクセス最適化の性質から、 オブジェクトの[[Prototype]]の変更は処理速度が遅いという特徴があります。 もしパフォーマンスを気にされるのであれば、 このメソッドまたはObject.setPrototypeOf(ES6で追加予定?)を使用し、 オブジェクトの[[Prototype]]を変更すべきではありません。 代わりに、Object.createを使用して、 必要とする[[Prototype]]を持つオブジェクトを作成してください。 更に、__proto__と__proto__のsetter関数は非推奨であるため、 使用すべきではありません。

継承のためにprototypeがどのように使用されるかを理解するには、 ガイドのInheritance and the prototype chainを参照してください。

__proto__プロパティは、特別な事は何もありません。 getter関数とsetter関数から成る、 Object.prototype上の単純なアクセサ(accessor)プロパティです。 "__proto__"へのアクセスするプロパティは、 最終的にはObject.prototypeを参照してこれを見つけますが、 Object.prototypeを参照しないアクセスは、それを見つけることは出来ません。 もし、Object.prototypeが参照される前に他の"__proto__"プロパティが見つかった場合、 そのプロパティがObject.prototype上で見つかったものを隠蔽します。

var noProto = Object.create(null);

print(typeof noProto.__proto__); // undefined
print(Object.getPrototypeOf(noProto)); // null

noProto.__proto__ = 17;

print(noProto.__proto__); // 17
print(Object.getPrototypeOf(noProto)); // null

var protoHidden = {};
Object.defineProperty(protoHidden, "__proto__",
       { value: 42, writable: true, configurable: true, enumerable: true });

print(protoHidden.__proto__); // 42
print(Object.getPrototypeOf(protoHidden) === Object.prototype); // true

例

下記は新しくEmployeeのインスタンスを作成し、 __proto__がコンストラクタのprototypeと同じオブジェクトであることを検証しています。

// コンストラクタとして使用される関数を定義
function Employee() {
  /* インスタンスの初期化 */
}

// Employeeの新しいインスタンスを作成
var fred = new Employee();

// 同一確認
fred.__proto__ === Employee.prototype; // 結果:true

この時点でfredはEmployeeを継承しますが、 fred.__proto__には異なるオブジェクトが割り当てられ、 それは変更することが可能です。

// 新しいオブジェクトを__proto__へ割り当て
fred.__proto__ = Object.prototype;

fredは、もはやEmployee.prototypeを継承せず、 直接Object.prototypeから継承し、 Employee.prototypeから継承していたプロパティは失われます。

ただし、これは拡張可能(extensible)なオブジェクトでのみ適用され、 拡張可能では無い(non–extensible)オブジェクトの__proto__プロパティを変更することは出来ません。

var obj = {};
Object.preventExtensions(obj);

obj.__proto__ = {}; // throws a TypeError

プロトタイプチェーンがnullに繋がってさえいれば、 Object.prototypeの__proto__プロパティでさえ、再定義することが可能です。

var b = {};

Object.prototype.__proto__ = {
    hi: function () {alert('hi');},
    __proto__: null
};

b.hi();

もし、Object.prototypeの__proto__にnullが設定されていない、 または最終的に明確にnullに繋がるプロトタイプチェーンを持たない他のオブジェクトが設定されていない場合、 最終的にはプロトタイプチェーンはnullへ繋がらなければならないため、"cyclic __proto__ value"のTypeErrorが発生します。 (通常はObject.prototype上で行います。)

仕様

ブラウザ互換性

デスクトップ
機能 Chrome Firefox
(Gecko)
IE Opera Safari
基本 ◯ ◯ ◯ ◯ ◯
モバイル
機能 Android Chrome for
Android
Firefox
Mobile
IE
Mobile
Opera
Mobile
Safari
Mobile
基本 ◯ ◯ ◯ ◯ ◯ ◯

 Back to top

© 2017 Mozilla Contributors
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.

このページは、ページトップのURL先のMozilla Developer Network(以下、MDN)のコンテンツを翻訳した内容を基に構成されています。 構成について異なる点も含まれますので、下記の項目を確認し、必要に応じて元のコンテンツをご確認ください。 もし、誤訳などの間違いを見つけましたら、 @tomofまで教えていただければ幸いです。

  • 特定のブラウザに特化しすぎている情報やあまりにも古い情報、 または試験的に導入されているようなAPIや機能については、省略していることがあります。
  • 例やデモについて、実際にページ内で動作させる関係で一部ソースコードを変更している場合や、 その例で使用しているコンテンツの単語や文章などを日本人向けに変更しいてる場合があります。
  • MDNの更新頻度が高いため、元のコンテンツと比べ情報が古くなっている可能性があります。
  • "訳注:"などの断わりを入れた上で、日本人向けの情報の追記を行っている事があります。