2017-01-04 6 views
2

JavaScriptでプロトタイプベースの継承を理解しようとしています。コンストラクタ関数とプロトタイプチェーンを確立するには、通常、このようにそれを実行します。型継承:プロトタイプを直接設定するのではなく、なぜ新しいオブジェクトを作成する必要がありますか?

function Person(name, gender){ 
    this.name = name; 
    this.gender = gender; 
} 

function Male(name){ 
    Person.call(this, name, "male"); 
} 

Male.prototype = Object.create(Person.prototype); 

Object.defineProperty(Male.prototype, "constructor", { 
    enumerable: false, value: Male, writeable: true 
}); 

var person1 = new Male("Chris"); 

ので、Male.prototypeのためにあなたが親オブジェクトに設定された内部[[プロトタイプ]]プロパティを持つ完全に新しいオブジェクトを作成します。これは新しいオブジェクトであるため、列挙できないconstructorプロパティを追加する必要があります。直接[[prototype]]プロパティを設定する方法があるので

は、私はあなたがこれを行うことはできませんなぜだろ:

function Person(name, gender){ 
    this.name = name; 
    this.gender = gender; 
} 

function Male(name){ 
    Person.call(this, name, "male"); 
} 

Object.setPrototypeOf(Male.prototype, Person.prototype); 

var person1 = new Male("Chris"); 

このソリューションを使用すると、ちょうど親オブジェクトにMale.prototype[[prototype]]プロパティを設定します。 (ES6の前に、__proto__プロパティを使用してプロトタイプを設定できました)新しいオブジェクトを作成する必要はありません(jsランタイムが自動的にがすべての関数に新しいprototypeオブジェクトを添付しています)正しいconstructorプロパティを明示的に作成する必要はありません。既に存在するためです。

私の質問です:なぜ誰もプロトタイプチェーンを設定するためにこのアプローチを使用しないのですか?問題はどこだ?

+0

FYIでは、第2引数を使って 'constructor'プロパティを定義することで、' Object.create'バージョンをもう少しきれいに行うことができます。 –

+0

'Object.defineProperty..'行は実際にコンストラクタを設定する一般的な方法ではありません。その全体の指示(3行)は単に次のようになります: 'Male.prototype.constructor = Person;' –

+0

@ScottMarcus:これはそれを列挙します。 'defineProperty'を使うと、正しいプロパティ記述子を設定できます。 –

答えて

-1

これは微妙ですが、非常に重要な点です。 MaleプロトタイプをPersonプロトタイプに設定した場合、は、というオブジェクトのONEインスタンスを共有します。 Personプロトタイプへの変更は、PersonMaleオブジェクトのすべてのインスタンスに影響します。とその逆の両方のインスタンスに影響します。さて、当初、これは望ましい動作のように思えますが、ここでは "タイプ"の概念を "インスタンス"とは別にしておく必要があります。

Maleを与えることによって、そのプロトタイプとしてPerson新しいインスタンスが、あなたは、を継承の利益を得るが、あなたのデカップルすべてPersonのインスタンスは、インスタンスから使用しているPersonの実際のインスタンスすべてのMaleインスタンスが使用することになります。

Male.prototypeを変更して、Personインスタンスに影響を与えずに変更することができます。

+0

* "'男性 'プロトタイプを' Person'プロトタイプに設定した場合... *これは、OPがやっていること以外は真実です。 OPは 'Object.prototype'のプロトタイプチェーンの次の項目を' Object.prototype'から 'Person.prototype'に切り替えるので、表面上は有効と思われますが、これが同じ性能を持つかどうかはわかりませんそのようにプロトタイプチェーンを変更する問題。 –

+0

@squint MDNは、パフォーマンスが非常に悪くなる可能性があると述べています。 –

+0

はい、私は一般的なケースでそれを認識していますが、これは個々のインスタンスではなく、コンストラクタ自体のプロトタイプチェーンの1回の変更です。私はテストなしでいずれの主張もしたくないです。 –

0

これは興味深い質問です。私はsetPrototypeOfメソッドの存在を知らなかった。明らかに、パフォーマンスはObject.createを使用する場合よりも悪いです。

パフォーマンスを気にする場合は、オブジェクトの[Prototype]を設定しないでください。 Object.create()を使用して、目的の[[Prototype]]で新しいオブジェクトを作成します。

developer.mozilla.org

0

からのリンクの詳細情報私は数日前に同じ疑問を持っていたし、私はここでそれについて尋ねた:https://softwareengineering.stackexchange.com/questions/343778/when-doing-inheritance-why-not-simply-modify-the-prototype-property-of-the

どうやら、「なぜ我々はshouldnのように本当のコンセンサスはありませんtはObject.setPrototypeOf(Child.prototype, Parent.prototype)ですが、Mozilla(MDN)からは一般的な警告があります。

警告:オブジェクトの[Prototype]の変更は、現代のJavaScriptエンジンがプロパティのアクセスを最適化する性質上、すべてのブラウザとJavaScriptエンジンで非常に遅い操作です。継承の変更のパフォーマンスへの影響は、微妙で遠くにあり、obj .__ proto__ = ...ステートメントで費やされた時間に限定されるものではありませんが、[[Prototype] ]が変更されました。パフォーマンスを気にするなら、オブジェクトの[[Prototype]]の設定は避けてください。 Object.create()を使用して、目的の[[Prototype]]で新しいオブジェクトを作成します。

ボトムライン:しないでください!

これはコード内の不確実性を繁殖させます。

関連する問題