3

質問:

  1. 最初のメソッドがオブジェクトをフェラーリとして正しく識別するのはなぜですか?(Chromeでテスト済み)
  2. 2つの方法で継承を正しく行っていますか?
  3. 最初の例にはいくつかの隠された「コンストラクター」プロパティがあることを理解して正しいですか?もしそうなら、それらはどこにあり、何がそれらをそこに置いたのですか?明示的に入力しなかった2番目の例に隠されたコンストラクタープロパティはありますか?
  4. 継承を正しく行った場合、オブジェクトをフェラーリとして識別させるために、最後に2つの方法のどちらを使用する必要がありますか?それとも私は気にしないでください-結局のところ「instanceof」はまだ機能しますか?

コンテクスト:

オブジェクトを作成するためのJavaScriptの「新しい」メソッドを使用すると、正常に機能します。

Vehicle.prototype = {}; // Not required I know
function Vehicle() {

}

Car.prototype = new Vehicle();
function Car() {

}

Ferrari.prototype = new Car();
function Ferrari() {

}
var o = new Ferrari();
console.log(o);

どの出力:

> Ferrari
  > __proto__ : Car
    > __proto__ : Vehicle
      > __proto__ : Object <- The one that isn't required
        > __proto__ : Object <- Provided by JS
          ...
          hasOwnProperty: function hasOwnProperty() { [native code] }
          ...

今、私は新しいキーワードを避けて同じことをしたいです、これが私が持っているものです:

Vehicle.prototype = {};
function Vehicle() {
  var vehicle = Object.create(Vehicle.prototype);
  return vehicle;
}

Car.prototype = Vehicle();
Car.prototype.constructor = Vehicle;
function Car() {
  var car = Object.create(Car.prototype);
  return car;
}

Ferrari.prototype = Car();
Ferrari.prototype.constructor = Car;

function Ferrari() {
  var ferrari = Object.create(Ferrari.prototype);
  //ferrari.constructor = Ferrari;  <- Lookey here - commented line
  return ferrari;
}

var o = new Ferrari();
console.log(o);

どの出力:

> **Car**
  > __proto__ : Car
    > constructor : function Car()
      __proto__ : Vehicle
      > constructor : function Vehicle()
        __proto__ : Object <- The one that isn't required
        > __proto__ : Object
          ...
          hasOwnProperty: function hasOwnProperty() { [native code] }
          ...

出力の最初の行がフェラーリではなく車になっていることに注意してください。これは、コメント行を削除するか、フェラーリのプロトタイプを次のように変更することで修正できます。

var realPrototype = Car();
realPrototype.constructor = Car;

Ferrari.prototype = Object.create(realPrototype);
Ferrari.prototype.constructor = Ferrari;
4

2 に答える 2

0

最初の方法でオブジェクトがフェラーリであると正しく識別されるのはなぜですか? (Chromeでテスト済み)

最初の例にいくつかの隠された「コンストラクター」プロパティがあることを理解するのは正しいですか? 明示的に入れていない 2 番目の例に、コンストラクターの隠しプロパティはありますか?

prototypeはい、関数のプロパティに割り当てるか、何らかの方法で新しいインスタンスを作成すると、Chrome は非表示の「コンストラクタ」プロパティを設定するようです。正確には把握していません。

彼らはどこにいますか?おそらくいくつかの内部プロパティにしかconsole.logアクセスできません。__proto__それでも、少なくともオブジェクトを表示するために、明示的な「コンストラクター」プロパティでそれらを上書きできるようです。

多くの人がプロトタイプ オブジェクトを上書きするときにコンストラクター プロパティを設定するのを忘れているため (実際には役に立たないため) 、これは Chrome によって行われていると思いますが、推奨されています - JavaScript の継承とコンストラクター プロパティも参照してください。Chromelog開発者は、オブジェクトのタイプを示すきれいな関数を作成したかったため、人々の怠惰を回避する必要がありました。

2 つの方法で継承を正しく行っていますか?

コードの継承に問題はありません。新しく作成されたCarインスタンスには、両方の方法で、熱望されたプロトタイプ チェーンがあります。

ただし、いくつかの落とし穴があります。newキーワードを使用してプロトタイプオブジェクトインスタンスを作成しないでください。コンストラクターが適用された本格的なインスタンスは必要ありません。使用するだけCar.prototype = Object.create(Vehicle.prototype)です。Derived.prototype = new Base で「new」キーワードを使用する理由は何ですかの回答も参照してください

また、「コンストラクター」プロパティを設定していないか、間違っています。プロトタイプ オブジェクトで定義されたそのプロパティは、それぞれのコンストラクタ関数の呼び出しによって作成されたすべてのオブジェクトに継承され、new正確にその関数への参照を提供する必要があります。これは、作成された関数に対してデフォルトで行われます。EcmaScript 仕様 §13.2 のステップ 16-18を参照してください。

に再割り当てするとfn.prototype、その動作が上書きされます (オブジェクト リテラル、new構築、Object.create呼び出しのいずれであっても)。事実上、「コンストラクター」プロパティは、プロトタイプチェーンの上位のオブジェクトから継承されます-最初の例o.constructorではObject、空のオブジェクトリテラルから継承されます。したがって、あなたの場合、割り当て後にリセットする必要があります。

Vehicle.prototype.constructor = Vehicle;
Car.prototype.constructor = Car;
Ferrari.prototype.constructor = Ferrari;

// or, we combine it with the Object.create call:
Car.prototype = Object.create(Vehicle.prototype, {
    constructor: {value:Car, configurable:true, writable:true}
});

オブジェクトに追加のプロパティを作成して、コンストラクターで明示的に設定する必要がないことに注意してください (2 番目の例のように)。これが継承の目的です。

または、「コンストラクター」プロパティをまったく気にしません。

オブジェクトがフェラーリであると識別できるようにするために、最後に使用する 2 つの方法のどれを使用すればよいですか? それとも気にしなくていいのですか?

オブジェクトをフェラーリとして識別するには、常に を使用しますinstanceof。「コンストラクター」プロパティは信頼できません。設定するのを忘れているか、比較で期待したものではない可能性があります。「型チェック」のようなものsomeObj.constructor === Carは、コンストラクタ プロパティが適切に設定されているフェラーリやその他の「サブクラス」では機能しません。で行いinstanceofます。

于 2012-12-09T23:05:03.047 に答える
-1

最初の方法でオブジェクトがフェラーリであると正しく識別されるのはなぜですか?

オブジェクトのコンストラクターoは function であるためですFerrari

2 つの方法で継承を正しく行っていますか?

最初の方法では正しく実行していますが、2 番目の方法では正しくありません。

継承を正しく行った場合、オブジェクトをフェラーリとして識別させるには、最後に 2 つの方法のどちらを使用すればよいでしょうか? それとも気にしなくていいのですか?

統一性のために、関数本体の各プロトタイプでコンストラクター プロパティを設定する必要があります。

Car.prototype = Vehicle();
Car.prototype.constructor = Vehicle;

Aeroplane.prototype = Vehicle();
Aeroplane.prototype.constructor = Vehicle;

...

代わりに、次を使用する必要があります。

function Vehicle() {
    var vehicle = Object.create(Vehicle.prototype);
    vehicle.constructor = Vehicle;
    return vehicle;
}

Car.prototype = Vehicle();
function Car() {
    var car = Object.create(Car.prototype);
    car.constructor = Car;
    return car;
}

Ferrari.prototype = Car();
function Ferrari() {
    var ferrari = Object.create(Ferrari.prototype);
    ferrari.constructor = Ferrari;
    return ferrari;
}

var o = new Ferrari();
console.log(o);

これにより、最初の例と同様の構造が正しく得られます。

于 2012-12-09T18:36:31.520 に答える