この記事は編集レビューを必要としています。ぜひご協力ください。
この記事は翻訳作業中です。
警告: オブジェクトの[[Prototype]]を変更することは、最新のJavaScriptエンジンがプロパティアクセスを最適化する仕組み上、すべてのブラウザやJavaScriptエンジンにおいて、とても低速な操作となります。プロトタイプの継承関係を変更することによる性能上の影響は微細で広範囲にわたり、単にobj.__proto__ = ...という文の実行時間に留まらず、[[Prototype]]が変更されたいずれかのオブジェクトへのアクセスを持つあらゆるコードに及ぶかもしれません。性能を気にしている場合、オブジェクトの[[Prototype]]の変更は避けるべきです。かわりに、Object.create()を使用して望み通りの[[Prototype]]をもつオブジェクトを新たに生成してください。
警告: Object.prototype.__proto__は現時点でほとんどのブラウザがサポートしていますが、そのプロパティの存在と正確な動作は、ウェブブラウザーの互換性を確保するためのレガシー機能として、ECMAScript 6で初めて標準化されました。かわりにObject.getPrototypeOf()だけを使用することが推奨されます。
概要
Object.prototypeの__proto__プロパティは、アクセスされるオブジェクトの内部の[[Prototype]](オブジェクトまたはnullのどちらか)を暴露するアクセサプロパティ(getter関数とsetter関数)です。
__proto__の使用は、論争の的になり、推奨されていません。EcmaScript言語仕様にもともとは含まれていませんでした。しかし、最新のブラウザはとにかくそれを実装することを決定しました。今日、__proto__ プロパティはECMAScript第6版言語仕様で標準化されました。そして、将来にサポートされます。それにもかかわらず、オブジェクトの[[Prototype]]を変化させることは、性能を気にしている場合避けるべき低速の操作です。
__proto__プロパティは、生成時に[[Prototype]]オブジェクトを設定するためにObject.create()のかわりとしてオブジェクトリテラルの定義で使用されます。参照: object initializer / literal syntax
構文
var shape = {}, circle = new Circle();
// Set the object prototype
shape.__proto__ = circle;
// Get the object prototype
console.log(shape.__proto__ === circle); // true
注意: それは、2つのアンダースコアがあり、5文字"proto"が続いて、さらに2つのアンダースコアが続きます。
説明
__proto__ getter 関数はオブジェクトの内部の[[Prototype]]の値を外部にさらします。オブジェクトリテラルを使用して生成されたオブジェクトに対して、この値はObject.prototypeです。配列リテラルを使用して生成されたオブジェクトに対して、この値はArray.prototypeです。関数に対して、この値はFunction.prototypeです。new funを使用して生成されたオブジェクトの対して、この値はfun.prototypeです。ここで、funはJavaScript (Array、Boolean、Date、 Number、 Object、 String等 —JavaScriptの進化として追加された新しいコンストラクタを含みます。)によって提供されるビルトインコンストラクタ関数の一つです。new funを使用して生成されたオブジェクトに対して、この値は常にfun.prototypeの値です。ここで、funはスクリプトで定義された関数です。(すなわち、新しい値がfun.prototypeに割り当てられている場合、以前生成されたfunインスタンスも[[Prototype]]として新しい値を持ち、__proto__とfun.prototypeとして同じアドレスを参照します)。
__proto__ setterでオブジェクトの[[Prototype]]は変化することができます。オブジェクトは、Object.isExtensible()に応じて拡張可能である必要があります。: 拡張可能ではない場合、TypeErrorがスローされます。与えられた値がオブジェクト、または、nullである必要があります。他の値を提供することは何もしません。
プロトタイプが継承のためにどのように使用されるかを理解するには、ガイド記事Inheritance and the prototype chainを参照してください。
__proto__ プロパティは、getter関数とsetter関数からなるObject.prototype 上の簡単なアクセスプロパティです。最終的にのObject.prototypeを参照する__proto__に対してのプロパティアクセスはこのプロパティを探します。しかし、Object.prototypeを参照しないアクセスはこのプロパティを探しません。Object.prototypeが参照される前にいくつかの他の__proto__プロパティが見つけられた場合、そのプロパティは、Object.prototype上で見つけられたプロパティを隠します。
var noProto = Object.create(null);
console.log(typeof noProto.__proto__); // undefined
console.log(Object.getPrototypeOf(noProto)); // null
noProto.__proto__ = 17;
console.log(noProto.__proto__); // 17
console.log(Object.getPrototypeOf(noProto)); // null
var protoHidden = {};
Object.defineProperty(protoHidden, "__proto__",
{ value: 42, writable: true, configurable: true, enumerable: true });
console.log(protoHidden.__proto__); // 42
console.log(Object.getPrototypeOf(protoHidden) === Object.prototype); // true
例
次の例では、Employeeの新しいインスタンスが生成され、__proto__がコンストラクタのprototypeと同じであることを示すためにテストを実施します。
// Declare a function to be used as a constructor
function Employee() {
/* initialise instance */
}
// Create a new instance of Employee
var fred = new Employee();
// Test equivalence
fred.__proto__ === Employee.prototype; // true
この時点で、fredはEmployeeから継承します。しかしながら、違うオブジェクトをfred.__proto__を割り当てることで変更できます。:
function Cow() {
/* initialise instance */
}
// Assign a new object to __proto__
fred.__proto__ = Cow.prototype;
今 fredはEmployee.prototypeのかわりにCow.prototypeから直接継承します。Employee.prototypeから元来継承されたプロパティを失います。
しかしながら、これは、extensibleオブジェクトに適用するのみで、拡張不可なオブジェクトの__proto__プロパティは変更されません。:
var obj = {};
Object.preventExtensions(obj);
obj.__proto__ = {}; // throws a TypeError
Object.prototypeの__proto__プロパティでさえ、連鎖がnullに続く限り再定義されることに注意して下さい。:
var b = {};
Object.prototype.__proto__ =
Object.create(null, // [[Prototype]]
{ hi: { value: function() { alert('hi'); } } });
b.hi();
Object.prototypeの__proto__が、nullに設定されない場合、または、プロトタイプチェーンが最終的に明示的にはnullにつながらない別のオブジェクトに設定されない場合、チェーンが最終的にnullにつながるので、"cyclic __proto__ value" TypeErrorがスローされます。 (それは通常どおりObject.prototype上です)。
仕様
| 仕様 | 状況 | コメント |
|---|---|---|
| ECMAScript 2015 (6th Edition, ECMA-262) Object.prototype.__proto__ の定義 |
標準 | Webブラウザのために追加ECMAScript機能の(規定)附属書に含まれています(仕様が既に実装されているものを体系化することに注意してください)。 |
ブラウザ実装状況
注意: ES6の仕様が、__proto__へのサポートがWebブラウザに必要であることを規定している間、(規範として奨励されていますが)他の環境では必要ではありません。コードがWebブラウザではない環境をサポートする必要がある場合、かわりに、Object.getPrototypeOf()とObject.setPrototypeOf()を使用することが推奨されています。
| 機能 | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
|---|---|---|---|---|---|
| 基本サポート | (有) | (有) | 11 | (有) | (有) |
| 機能 | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|---|
| 基本サポート | (有) | (有) | (有) | (有) | (有) | (有) |