This translation is incomplete. この記事の翻訳にご協力ください
Object.create() メソッドは、既存のオブジェクトを新しく生成されるオブジェクトのプロトタイプとして使用して、新しいオブジェクトを生成します。
このデモのソースファイルは GitHub リポジトリに格納されています。デモプロジェクトに協力したい場合は、 https://github.com/mdn/interactive-examples をクローンしてプルリクエストを送信してください。
構文
Object.create(proto, [propertiesObject])
引数
proto- 新たに生成されるオブジェクトのプロトタイプになるべきオブジェクトです。
propertiesObjectOptional- 指定されていて、
undefinedでない場合、それ自身が所有する一連の列挙可能なプロパティ ( own property — つまり、それ自身に定義されていて、プロトタイプチェインの中では列挙可能でないプロパティ) が、それらのプロパティ名を伴う一連のプロパティ記述子を指定し、新たに生成されるオブジェクトに追加されることになります。これらのプロパティは、Object.defineProperties()の2番目の引数に対応するものです。
返値
指定したプロトタイプオブジェクトとプロパティを持つ新しいオブジェクトです。
例外
引数 propertiesObject が null かオブジェクトではない場合、 TypeError 例外が発生します。
例
Object.create() を用いた古典的な継承
以下の例は、古典的な継承をするための Object.create() の使用方法です。これは、すべての JavaScript が対応している単一継承です。
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
//If you don't set Object.prototype.constructor to Rectangle,
//it will take prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;
var 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); // Outputs, 'Shape moved.'
複数のオブジェクトから継承したい場合は、ミックスインが可能です。
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}
// inherit one class
MyClass.prototype = Object.create(SuperClass.prototype);
// mixin another
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// re-assign constructor
MyClass.prototype.constructor = MyClass;
MyClass.prototype.myMethod = function() {
// do something
};
Object.assign() は OtherSuperClass プロトタイプから MyClass プロトタイプへプロパティをコピーし、 MyClass のすべてのインスタンスで利用できるようにします。 Object.assign() は ES2015 で導入され、ポリフィルを利用することができます。古いブラウザーへの対応が必要な場合は、 jQuery.extend() または _.assign() を利用することができます。
Object.create() と propertiesObject 引数の併用
var o;
// プロトタイプを null にしてオブジェクトを生成
o = Object.create(null);
o = {};
// is equivalent to:
o = Object.create(Object.prototype);
// Example where we create an object with a couple of
// sample properties. (Note that the second parameter
// maps keys to *property descriptors*.)
o = Object.create(Object.prototype, {
// foo is a regular 'value property'
foo: {
writable: true,
configurable: true,
value: 'hello'
},
// bar is a getter-and-setter (accessor) property
bar: {
configurable: false,
get: function() { return 10; },
set: function(value) {
console.log('Setting `o.bar` to', value);
}
/* with ES2015 Accessors our code can look like this
get() { return 10; },
set(value) {
console.log('Setting `o.bar` to', value);
} */
}
});
function Constructor() {}
o = new Constructor();
// is equivalent to:
o = Object.create(Constructor.prototype);
// Of course, if there is actual initialization code
// in the Constructor function,
// the Object.create() cannot reflect it
// Create a new object whose prototype is a new, empty
// object and add a single property 'p', with value 42.
o = Object.create({}, { p: { value: 42 } });
// by default properties ARE NOT writable,
// enumerable or configurable:
o.p = 24;
o.p;
// 42
o.q = 12;
for (var prop in o) {
console.log(prop);
}
// 'q'
delete o.p;
// false
// to specify an ES3 property
o2 = Object.create({}, {
p: {
value: 42,
writable: true,
enumerable: true,
configurable: true
}
});
/* is equivalent to:
o2 = Object.create({p: 42}) */
カスタムオブジェクトと Null オブジェクト
A new object created from a completely custom object (especially one created from the null object, which is basically a custom object with NO members) can behave in unexpected ways. This is especially true when debugging, since common object-property converting/detecting utility functions may generate errors, or simply lose information (especially if using silent error-traps that ignore errors). For example, here are two objects:
oco = Object.create( {} ); // create a normal object
ocn = Object.create( null ); // create a "null" object
> console.log(oco) // {} -- Seems normal
> console.log(ocn) // {} -- Seems normal here too, so far
oco.p = 1; // create a simple property on normal obj
ocn.p = 0; // create a simple property on "null" obj
> console.log(oco) // {p: 1} -- Still seems normal
> console.log(ocn) // {p: 0} -- Still seems normal here too. BUT WAIT...
As shown above, all seems normal so far. However, when attempting to actually use these objects, their differences quickly become apparent:
> "oco is: " + oco // shows "oco is: [object Object]" > "ocn is: " + ocn // throws error: Cannot convert object to primitive value
Testing just a few of the many most basic built-in functions shows the magnitude of the problem more clearly:
> alert(oco) // shows [object Object]
> alert(ocn) // throws error: Cannot convert object to primitive value
> oco.toString() // shows [object Object]
> ocn.toString() // throws error: ocn.toString is not a function
> oco.valueOf() // shows {}
> ocn.valueOf() // throws error: ocn.valueOf is not a function
> oco.hasOwnProperty("p") // shows "true"
> ocn.hasOwnProperty("p") // throws error: ocn.hasOwnProperty is not a function
> oco.constructor // shows "Object() { [native code] }"
> ocn.constructor // shows "undefined"
As said, these differences can make debugging even simple-seeming problems quickly go astray. For example:
A simple common debugging function:
// display top-level property name:value pairs of given object
function ShowProperties(obj){
for(var prop in obj){
console.log(prop + ": " + obj[prop] + "\n" );
}
}
Not such simple results: (especially if silent error-trapping had hidden the error messages)
ob={}; ob.po=oco; ob.pn=ocn; // create a compound object using the test objects from above as property values
> ShowProperties( ob ) // display top-level properties
- po: [object Object]
- Error: Cannot convert object to primitive value
Note that only first property gets shown.
(But if the same object is created simply in a different order -- at least in some implementations...)
ob={}; ob.pn=ocn; ob.po=oco; // create same compound object again, but create same properties in different order
> ShowProperties( ob ) // display top-level properties
- Error: Cannot convert object to primitive value
Note that neither property gets shown.
Note that such a different order may arise statically via disparate fixed codings such as here, but also dynamically via whatever the order any such property-adding code-branches actually get executed at runtime as depends on inputs and/or random-variables. Then again, the actual iteration order is not guaranteed no matter what the order members are added.
Some NON-solutions
A good solution for the missing object-methods is not immediately apparent.
Adding the missing object-method directly from the standard-object does NOT work:
ocn = Object.create( null ); // create "null" object (same as before)
ocn.toString = Object.toString; // since new object lacks method then try assigning it directly from standard-object
> ocn.toString // shows "toString() { [native code] }" -- missing method seems to be there now
> ocn.toString == Object.toString // shows "true" -- method seems to be same as the standard object-method
> ocn.toString() // error: Function.prototype.toString requires that 'this' be a Function
Adding the missing object-method directly to new object's "prototype" does not work either, since the new object does not have a real prototype (which is really the cause of ALL these problems) and one cannot be directly added:
ocn = Object.create( null ); // create "null" object (same as before)
ocn.prototype.toString = Object.toString; // Error: Cannot set property 'toString' of undefined
ocn.prototype = {}; // try to create a prototype
ocn.prototype.toString = Object.toString; // since new object lacks method then try assigning it from standard-object
> ocn.toString() // error: ocn.toString is not a function
Adding the missing object-method by using the standard-object as new object's prototype does not work either:
ocn = Object.create( null ); // create "null" object (same as before) Object.setPrototypeOf(ocn, Object); // set new object's prototype to the standard-object > ocn.toString() // error: Function.prototype.toString requires that 'this' be a Function
Some OK solutions
Again, adding the missing object-method directly from the standard-object does NOT work. However, adding the generic method directly, DOES:
ocn = Object.create( null ); // create "null" object (same as before)
ocn.toString = toString; // since new object lacks method then assign it directly from generic version
> ocn.toString() // shows "[object Object]"
> "ocn is: " + ocn // shows "ocn is: [object Object]"
ob={}; ob.pn=ocn; ob.po=oco; // create a compound object (same as before)
> ShowProperties(ob) // display top-level properties
- po: [object Object]
- pn: [object Object]
However, setting the generic prototype as the new object's prototype works even better:
ocn = Object.create( null ); // create "null" object (same as before) Object.setPrototypeOf(ocn, Object.prototype); // set new object's prototype to the "generic" object (NOT standard-object)
(In addition to all the string-related functions shown above, this also adds:)
> ocn.valueOf() // shows {}
> ocn.hasOwnProperty("x") // shows "false"
> ocn.constructor // shows "Object() { [native code] }"
// ...and all the rest of the properties and methods of Object.prototype.
As shown, objects modified this way now look very much like ordinary objects.
ポリフィル
このポリフィルは、プロトタイプは選択されたが第二引数を考慮しない状況向けに、新規オブジェクトを生成する主要な利用法に対応します。
実際の ES5 の Object.create では、[[Prototype]] として null を設定することがサポートされていますが、このポリフィルは ECMAScript5 以前のサポートをする制約上、null を使用できないことに注意してください。
if (typeof Object.create !== "function") {
Object.create = function (proto, propertiesObject) {
if (typeof proto !== 'object' && typeof proto !== 'function') {
throw new TypeError('Object prototype may only be an Object: ' + proto);
} else if (proto === null) {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
}
if (typeof propertiesObject != 'undefined') {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
}
function F() {}
F.prototype = proto;
return new F();
};
}
仕様書
| 仕様書 | 状態 | 備考 |
|---|---|---|
| ECMAScript (ECMA-262) Object.create の定義 |
現行の標準 | |
| ECMAScript 2015 (6th Edition, ECMA-262) Object.create の定義 |
標準 | |
| ECMAScript 5.1 (ECMA-262) Object.create の定義 |
標準 | 初回定義。 JavaScript 1.8.5 で実装。 |
ブラウザーの互換性
| デスクトップ | モバイル | サーバー | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
create | Chrome 完全対応 5 | Edge 完全対応 12 | Firefox 完全対応 4 | IE 完全対応 9 | Opera 完全対応 11.6 | Safari 完全対応 5 | WebView Android 完全対応 1 | Chrome Android 完全対応 18 | Firefox Android 完全対応 4 | Opera Android 完全対応 12 | Safari iOS 完全対応 5 | Samsung Internet Android 完全対応 1.0 | nodejs 完全対応 あり |
凡例
- 完全対応
- 完全対応