このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
Object.setPrototypeOf()
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2015年9月.
Object.setPrototypeOf() は静的メソッドで、指定されたオブジェクトのプロトタイプ(つまり、内部の[[Prototype]] プロパティ)を、別のオブジェクトまたはnull に設定します。
警告:オブジェクトの[[Prototype]] を変更すると、最近の JavaScript エンジンがプロパティへのアクセスを最適化する方法の特質上、すべてのブラウザーや JavaScript エンジンで、操作がとても低速になります。さらに、プロトタイプを変更することの性能への影響は細かく広範囲にわたり、Object.setPrototypeOf(...) 文に費やされる時間だけではなく、[[Prototype]] が変更されたすべてのオブジェクトへのアクセスを持つすべてのコードに影響する可能性があります。詳しくはJavaScript engine fundamentals: optimizing prototypes をお読みください。
この機能は言語の一部であるため、その機能の実装による負荷は (理念上は) エンジンの開発者によります。エンジンの開発者がこの問題に対処するまでの間、性能が気になる場合は、オブジェクトの[[Prototype]] を変更することは避けるべきです。代わりに、Object.create() を使用して必要な[[Prototype]] をもつオブジェクトを生成してください。
In this article
試してみましょう
const obj = {};const parent = { foo: "bar" };console.log(obj.foo);// 予想される結果: undefinedObject.setPrototypeOf(obj, parent);console.log(obj.foo);// 予想される結果: "bar"構文
Object.setPrototypeOf(obj, prototype)引数
返値
指定されたオブジェクト。
例外
TypeError以下のいずれかの場合に発生します。
- 引数
objがundefinedまたはnullである場合。 - 引数
objが拡張不可能であるか、またはプロトタイプが不変のエキゾチックオブジェクト、例えばObject.prototypeやwindow等の場合。ただし、新しいプロトタイプがobjの元のプロトタイプと同じ値である場合は、エラーは発生しません。 - 引数
prototypeがオブジェクトまたはnullではない場合。
- 引数
解説
Object.setPrototypeOf() は、一般的にオブジェクトのプロトタイプを設定するための適切な方法と考えられています。非推奨のObject.prototype.__proto__ アクセサーの代わりに、常にこれを使用するべきでしょう。
もし引数obj がオブジェクト(例えば、数値、文字列など)でない場合、このメソッドは何もせず、オブジェクトに変換したり、プロトタイプを設定することなく、直接obj をプリミティブ値として返します。もしprototype がobj のプロトタイプと同じ値であれば、obj のプロトタイプが不変であってもTypeError は発生せずにobj が直接返されます。
セキュリティの観点から、プロトタイプが不変であるように設計された組み込みオブジェクトがあります。これにより、プロトタイプ汚染攻撃、特にブロキシー関連の攻撃を防ぐことができます。コア言語では、不変のプロトタイプを持つエキゾチックオブジェクトとしてObject.prototype のみを指定しており、そのプロトタイプは常にnull です。ブラウザーでは、window やlocation の 2 つがとても一般的な例です。
Object.isExtensible(Object.prototype); // true。プロパティを追加できるObject.setPrototypeOf(Object.prototype, {}); // TypeError: 不変のプロトタイプオブジェクト '#<Object>' にプロトタイプを設定することはできないObject.setPrototypeOf(Object.prototype, null); // エラーなし。 `Object.prototype` のプロパティがすでに `null` であるため例
>Object.setPrototypeOf() を使った擬似クラス継承
クラスを使用した JS の継承です。
class Human {}class SuperHero extends Human {}const superMan = new SuperHero();しかし、class を使わずにサブクラスを実装したい場合は、次のようにします。
function Human(name, level) { this.name = name; this.level = level;}function SuperHero(name, level) { Human.call(this, name, level);}Object.setPrototypeOf(SuperHero.prototype, Human.prototype);// `SuperHero.prototype` の `[[Prototype]]` を `Human.prototype` に設定// プロトタイプのインスタンスチェーンを設定するためHuman.prototype.speak = function () { return `${this.name} says hello.`;};SuperHero.prototype.fly = function () { return `${this.name} is flying.`;};const superMan = new SuperHero("Clark Kent", 1);console.log(superMan.fly());console.log(superMan.speak());上記のような古典的継承(クラスによる継承)と擬似古典的継承(コンストラクターのprototype プロパティによる継承)の類似性については、継承チェーンで述べられています。
関数コンストラクターのprototype プロパティは書き込み可能なので、Object.create() で作成した新しいオブジェクトに再割り当てすることで、同じ継承連鎖を実現できます。create() を使用する際には、constructor プロパティを再度追加することを忘れないようにするなどの注意点があります。
以下の例でもクラスを使用していますが、SuperHero はextends を使用せずに、代わりにsetPrototypeOf() を使用してHuman を継承しています。
警告:extends の代わりにsetPrototypeOf() を使うことは、パフォーマンスや可読性の点からお勧めできません。
class Human {}class SuperHero {}// 継承プロパティを設定Object.setPrototypeOf(SuperHero.prototype, Human.prototype);// 静的プロパティをフックObject.setPrototypeOf(SuperHero, Human);const superMan = new SuperHero();extends を使わないサブクラス化は、ES-6 subclassing で触れられています。
仕様書
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-object.setprototypeof> |