Crockford は、次のようなObject.create
シムを推奨しています。
if (typeof Object.create != "function") {
Object.create = function (o) {
function F(){}
F.prototype = o;
return new F;
};
}
しかし、これをしないでください。
このアプローチの問題は、ES5が2 つの引数Object.create
の署名を持っていることです。1つ目は継承元のオブジェクト、2 つ目 (オプション) は、新しく作成されたオブジェクトに追加するプロパティ (または記述子) を表すオブジェクトです。
Object.create(O[, Properties]); // see 15.2.3.5, ECMA-262 5th ed.
私たちが持っているのは、2 つの異なる動作を持つ一貫性のない実装です。native のある環境ではObject.create
、メソッドは 2 番目の引数の処理方法を知っています。nativeObject.create
のない環境では、そうではありません。
実際的な意味は何ですか?
を使用したいコード (たとえば、サードパーティのスクリプト) がある場合Object.create
、そのコードがこれを行うのはかなり合理的です。
if (Object.create) {
var child = Object.create(parent, properties);
}
— 基本的に、存在する場合は仕様に準拠する必要があると仮定しObject.create
ます — 2 番目の引数を受け入れ、対応するプロパティをオブジェクトに追加します。
しかし、上記の shim では、2 番目の引数は単純に無視されます。何かが起こっている兆候すらありません違う違う。いわば静かな失敗 — 検出して修正するのはかなり面倒なことです。
もっとうまくやれるでしょうか?
(標準の) ES3 機能のみを使用して完全に準拠したシムを作成することは、Object.create
実際には不可能です。最善の解決策は、カスタム ラッパー メソッドを作成することです。
ただし、試すことができる代替の (最適とは言えない) ものはほとんどありません。
1) 2 番目の引数を使用できないことをユーザーに通知する
if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw Error('second argument is not supported');
}
// ... proceed ...
};
}
2) 2 番目の引数の処理を試みます。
if (!Object.create) {
Object.create = function (parent, properties) {
function F(){}
F.prototype = parent;
var obj = new F;
if (properties) {
// ... augment obj ...
}
return obj;
};
}
「プロパティ」は、プロパティの名前/値だけでなく、プロパティ記述子を表すオブジェクトであり、サポートするのがそれほど簡単ではないことに注意してください (プロパティの列挙可能性の制御など、いくつかのことは不可能です)。
Object.create(parent, {
foo: {
value: 'bar',
writable: true
},
baz: {
get: function(){ return 'baz getter'; },
set: function(value){ return 'baz setter'; },
enumerable: true
}
});
元の shim の他の矛盾は、親オブジェクトがnull
であることを考慮していないことです。
var foo = Object.create(null);
これにより、[[Prototype]] がnull
;であるオブジェクトが作成されます。Object.prototype
言い換えれば、 (ECMAScript のすべてのネイティブ オブジェクトが継承する)何からも継承しないオブジェクトです。
foo.toString; // undefined
foo.constructor; // undefined
// etc.
ところで、これは ECMAScript で「適切な」ハッシュ テーブルを作成するのに役立ちます。
この動作をエミュレートすることは可能ですが、「魔法の」プロパティなどの非標準の拡張機能のみを使用し __proto__
ます (そのため、実装は移植性や堅牢性に欠けます)。この問題の解決策は似ています: ES5 実装を完全にエミュレートするか、不整合/失敗について通知します。