1

次の正規のobject.createメソッドについて質問があります。

Object.create = function(o, props) {
    function F() {}
    F.prototype = o;

    if (typeof(props) === "object") {
     for (prop in props) {
      if (props.hasOwnProperty((prop))) {
       F[prop] = props[prop];
      }
     }
    }
    return new F();
   };

上記のコードの3行目で、Fオブジェクトのプロトタイププロパティをo引数のプロトタイプに設定します。

これは、oとFの両方が同じプロトタイプを指しているため、同じメンバーのセットを指していることを意味すると思います。

しかし、コードはその後、propsループ内のpropのすべてのメンバーをコピーします。

次に、すべてのメンバーを手動でコピーする場合、3行目にプロトタイプを設定する意味は何ですか?

4

3 に答える 3

1

提示するコードは、ECMA標準で定義されているものと同等ではありません。Object.create()2番目のパラメーターのメンバー(ここでは、と呼ばれpropます)は、コンストラクター関数にコピーされるのではなく、結果のオブジェクトで定義される記述子のセットであると想定されています。これはより正確です(ただし、正確には正しくありません)、

Object.create = function(o, props) { 
    function F() {} 
    F.prototype = o; 
    var result = new F();
    if (typeof(props) === "object") 
       for (prop in props)
          if (props.hasOwnProperty(prop) && typeof(props[prop].value) != "undefined")
             result[prop] = props[prop].value; 
    return result;
}; 

propsパラメータには、プロトタイプで指定されたものとは異なる新しいオブジェクトのメンバーのプロパティ記述子が含まれていますo。値は文字通りオブジェクトにコピーされることは想定されておらず、記述子の一部を新しいオブジェクトにObject.defineProperties()割り当てることによってシミュレートされた、上記のように呼び出されたかのように処理されることになっています。ECMA 3はアクセサ関数を使用してプロパティを指定するために使用できるため、ECMA 3に正確にポリフィルすることはできませんが、上記はまたはの代わりに使用する場合に機能します。valueObject.create()propsvaluegetset

ポリフィルバージョンに興味がない場合は、とObject.create()の両方が存在することを前提として、以下は何を行うかについての正確な説明です。__proto__Object.defineProperties()

Object.create = function (o, props) {
    if (typeof(o) !== "object" && o != null) throw new TypeError();
    var result = new Object();
    if (o != null)
        result.__proto__ = o;
    if (typeof(props) !== "undefined")
        Object.defineProperties(result, props);
    return result;
};
于 2012-09-06T08:46:16.390 に答える
1

質問のバージョンに誤りがありObject.createます。ループは、プロパティをコンストラクター関数にアタッチしますF(返されたオブジェクトやそのプロトタイプではありません)。つまり、作成されたオブジェクトではアクセスできません。

2番目のパラメータのプロパティはObject.create、新しく作成されたオブジェクトにコピーされることになっています。のMozillaドキュメントでObject.createは、次のようになっています。

指定され、未定義でない場合、列挙可能な独自のプロパティ(つまり、それ自体で定義され、プロトタイプチェーンに沿った列挙可能なプロパティではないプロパティ)を持つオブジェクトは、対応するプロパティ名とともに、新しく作成されたオブジェクトに追加されるプロパティ記述子を指定します。

Object.create質問のバージョンで次のコードを実行してみてください。

o = Object.create(
        {a: "prototype's a", b: "prototype's b"},
        {a: "object's a"}
    );

あなたはそれを見つけるでしょうo.a == "prototype's a"そしてo.b == "prototype's b""object's a"は失われます。

次のバージョンの関数の方がおそらく便利です。

Object.create = function(o, props) {
    var newObj;

    // Create a constructor function, using o as the prototype
    function F() {}
    F.prototype = o;

    // Create a new object using F as the constructor function
    newObj = new F();

    // Attach the properties of props to the new object
    if (typeof(props) === "object") {
        for (prop in props) {
            if (props.hasOwnProperty((prop))) {
                newObj[prop] = props[prop];
            }
        }
    }

    return newObj;
};

同じ例で試してみましょう。

o = Object.create(
        {a: "prototype's a", b: "prototype's b"},
        {a: "object's a"}
    );

新しいオブジェクトは、プロパティとそれ自体のプロパティoを持つプロトタイプで作成されます。aba

o.b最初に見てみましょう:。というプロパティがないため、o.hasOwnProperty("b")が返されます。そこでプロトタイプが登場します。プロパティがないため、プロトタイプで検索されます。したがって、。falseobbo.b === "prototype's b"

一方、プロパティがあるため、o.hasOwnProperty("a")が返されます。 プロトタイプからは何も検索されません。trueoao.a == "object's a"

@chuckjの回答で指摘されているように、の正しい実装Object.createはこれよりも複雑です。詳細については、ECMAScript5のオブジェクトとプロパティに関するJohnResigの投稿を参照してください。

于 2012-09-06T08:48:47.023 に答える
0

オブジェクトの新しいインスタンスと、新しいインスタンスがプロパティを借用しているオブジェクトへの参照をF返す関数と考えてください。F.prototype

で作成されたインスタンスにFは、に依存しない独自のプロパティセットがありF.prototypeます。

の時点でプロパティが見つからない場合F、ランタイムはプロトタイプチェーンをステップアップし、プロパティがに存在するかどうかを確認しますF.prototype

これが、一部をコピーして他を継承したい理由です。

プロトタイプのポイントは、クラスのようなコードの再利用/プロパティストレージを提供することです。

F.prototypeのクラスインスタンスをFオブジェクトと考えてください。

于 2012-09-06T08:18:11.743 に答える