Object.create()

Object.create() 静的メソッドは、既存のオブジェクトを新しく生成されるオブジェクトのプロトタイプとして使用して、新しいオブジェクトを生成します。

試してみましょう

構文

js
Object.create(proto)
Object.create(proto, propertiesObject)

引数

proto

新たに生成されるオブジェクトのプロトタイプになるべきオブジェクトです。

propertiesObject 省略可

指定されていて、 undefined でない場合、それ自身の列挙可能なプロパティが、それらのプロパティ名を伴う一連のプロパティ記述子を指定し、新たに生成されるオブジェクトに追加されることになります。これらのプロパティは、 Object.defineProperties() の 2 番目の引数に対応するものです。

返値

指定したプロトタイプオブジェクトとプロパティを持つ新しいオブジェクトです。

例外

TypeError

protonull でも Object でもない場合に発生します。

Object.create() を用いた古典的な継承

以下の例は、古典的な継承をするための Object.create() の使用方法です。これは、すべての JavaScript が対応している単一継承です。

js
// Shape - スーパークラス
function Shape() {
  this.x = 0;
  this.y = 0;
}

// スーパークラスのメソッド
Shape.prototype.move = function (x, y) {
  this.x += x;
  this.y += y;
  console.info("Shape moved.");
};

// Rectangle - サブクラス
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// サブクラスはスーパークラスを拡張する
Rectangle.prototype = Object.create(Shape.prototype, {
  // Rectangle.prototype.constructor を Rectangle に設定しないと、
  // Shape (親) の prototype.constructor を取ることになります。
  // これを防ぐために、 prototype.constructor を Rectangle (子) に設定します。
  constructor: {
    value: Rectangle,
    enumerable: false,
    writable: true,
    configurable: true,
  },
});

const rect = new Rectangle();

console.log("Is rect an instance of Rectangle?", rect instanceof Rectangle); // true
console.log("Is rect an instance of Shape?", rect instanceof Shape); // true
rect.move(1, 1); // 'Shape moved.' と出力

create() を使用する際には、確実に適切な意味づけをするために constructor プロパティを追加し直すなどの注意点があることに注意してください。 Object.create()Object.setPrototypeOf() でプロトタイプを変更するよりもパフォーマンスが良いと信じられていますが、インスタンスが作成されておらず、プロパティアクセスがまだ最適化されていない場合、その差は実際にはごくわずかです。現行の JavaScript コードでは、どのような場合でも class 構文を推奨します。

Object.create() と propertiesObject 引数の併用

Object.create() はオブジェクトの作成プロセスを細かく制御することができます。オブジェクト初期化構文Object.create()の糖衣構文です。 Object.create() を使うと、指定したプロトタイプとプロパティを持つオブジェクトを作成することができます。 2 つ目の引数は プロパティ記述子 に割り当てられたキーであることに注意してください。これは、オブジェクト初期化子ではできない、各プロパティの列挙可能性や設定可能性なども制御できることを意味しています。

js
o = {};
// これは次のものと同等
o = Object.create(Object.prototype);

o = Object.create(Object.prototype, {
  // foo は普通のデータプロパティ
  foo: {
    writable: true,
    configurable: true,
    value: "hello",
  },
  // bar はアクセサープロパティ
  bar: {
    configurable: false,
    get() {
      return 10;
    },
    set(value) {
      console.log("Setting `o.bar` to", value);
    },
  },
});

// プロトタイプが新規の空オブジェクトである新しいオブジェクトを
// 生成し、単一のプロパティ 'p' を値を 42 にして追加します。
o = Object.create({}, { p: { value: 42 } });

Object.create() を使用すると、 null をプロトタイプとするオブジェクトを作成することができます。オブジェクトの初期化子では、 __proto__ キーが同等の構文になります。

js
o = Object.create(null);
// Is equivalent to:
o = { __proto__: null };

既定では、プロパティは書き込み可能でも、列挙可能でも、設定可能でもありません。

js
o.p = 24; // 厳格モードでは例外発生
o.p; // 42

o.q = 12;
for (const prop in o) {
  console.log(prop);
}
// 'q'

delete o.p;
// false; 厳格モードでは例外発生

初期化子と同じ属性を持つプロパティを指定するには、writableenumerableconfigurable を明示的に指定してください。

js
o2 = Object.create(
  {},
  {
    p: {
      value: 42,
      writable: true,
      enumerable: true,
      configurable: true,
    },
  },
);
// これは次のものと等価です。
// o2 = Object.create({ p: 42 })
// which will create an object with prototype { p: 42 }

Object.create() を使用して new 演算子の動作を模倣することができます。

js
function Constructor() {}
o = new Constructor();
// 次のものと等価です。
o = Object.create(Constructor.prototype);

もちろん、 constructor 関数の中に実際の初期化コードがある場合、 Object.create() メソッドにそれを反映させることはできません。

仕様書

Specification
ECMAScript Language Specification
# sec-object.create

ブラウザーの互換性

BCD tables only load in the browser

関連情報