プロトタイプを作成するときにコンストラクターの使用が推奨されないのはなぜですか?


10

背景: JavaScriptでは、各オブジェクトタイプのコンストラクター関数にprototypeプロパティがあります。prototypeオブジェクトを参照する、そのプロトタイプチェーン内の次のステップアップとしてそれぞれ構成されたオブジェクトの使用。あるタイプを別のタイプから組み込みたい場合prototypeは、子タイプのを親タイプの新しいインスタンスに設定できます。

例えば:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

私の質問はSome prototype object goes here、上記のコードの「」の場所にどのコードを配置する必要があるかを尋ねています。私の最初の本能は親のインスタンス(つまりnew Parent())を構築することですが、これはあるオブジェクトのプロトタイプを別のオブジェクトのプロトタイプにコピーする安全な方法ですか?、1人のユーザーが書き込みます:

いいえ、new bar()プロトタイプオブジェクトには使用しないでください。

(...これは多くのSOの回答やコメントで見た意見ですが、これが現時点で手にしている唯一の例です。)

もう1つのオプションは、Object.create(Parent.prototype)として使用することChild.prototypeです。私の知る限り、これによって新しいParentインスタンスも作成されますが、Parentコンストラクターは実行されません。

親タイプからプロトタイプオブジェクトを生成するときにコンストラクタ関数の実行を回避する必要がある理由を誰かが説明できますか?(おそらく複数の継承レベルで)発生するいくつかの重大な技術的問題はありますか?または、そのようなパターンは、プロトタイプのベストプラクティスと衝突するコンストラクタの誤用ですか(たとえば、プロトタイプの作成時にコンストラクタを実行すると、懸念の分離に違反します)?

回答:


5

呼び出す必要のない関数だからです。newJavaScriptの通常の関数呼び出しとそれほど違いはありません。

コンストラクタは、単にフィールドを設定するだけではありません。たとえば、受信データを検証する場合、継承チェーンを設定しようとしただけで検証エラーが発生します。

そして、あなたは必要ありませんObject.create、これで十分です:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}

しかし、それObject.createはまさに実装されている方法です。
ケーシーチュー

@CaseyChuはまったくありません。リンクされた投稿で誰かが「Object.createIE8 では機能しない」と言ったので、私はそれを言及しました。これは、任意のブラウザーで2秒でこのユースケースに実装できるときの役に立たないコメントです。
エサイリヤ2013年

2

私の理解が少し広がったので、具体的な例を挙げてエサイリアの答えにしたいと思います。

特定の問題の1つは、コンストラクターがインスタンス固有のプロパティを設定できることです。したがって、で作成されたプロトタイプオブジェクトを使用する場合new、すべての子インスタンスは、プロトタイプからの単一のコンストラクター定義のインスタンス固有のプロパティを共有できます。

たとえば、Parentインスタンスごとに一意のidプロパティが構築時間として設定されているとします。

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

これにより、すべての Childインスタンスが、として使用されるid唯一のnew Parent()オブジェクトから継承された単一のプロトタイププロパティを共有ますChild.prototype

この場合のより良いアプローチはObject.create、子コンストラクター内で親コンストラクターを使用して直接呼び出すことです(必要な場合)。

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run `this` through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.