JavaScriptのプロトタイプ継承の規則
-
03-07-2019 - |
質問
次のようなコードがたくさんあります:
function Base() {}
function Sub() {}
Sub.prototype = new Base();
ただし、次の場合:
s = new Sub();
print(s.constructor == Sub);
これは偽です。 sのコンストラクターは確かにSubであるため、これは私を混乱させるようです。これを行うのは従来型/より良いですか?
function Base() {}
function Sub() {}
Sub.prototype = new Base();
Sub.prototype.constructor = Sub;
またはそれは本当に重要ではありませんか?
解決
'constructor'は、見た目どおりに動作しません。これは、その非標準性に加えて、それを使用しないようにする正当な理由です-instanceofとprototypeに固執します。
技術的に:「コンストラクタ」は「s」インスタンスのプロパティではなく、「Sub」プロトタイプオブジェクトのプロパティであり、透けて見えます。 Mozillaで 'Sub'関数を作成すると、新しく作られたデフォルトのSub.prototypeオブジェクトを取得します。このオブジェクトには、Sub関数を礼儀として指す「コンストラクタ」があります。
ただし、そのプロトタイプを新しいBase()に置き換えます。 Subに戻るリンクを持つ元のデフォルトプロトタイプは失われます。代わりに、Sub.prototypeは、オーバーライドする「コンストラクター」プロパティのないBaseのインスタンスです。だから:
new Sub().constructor===
Sub.prototype.constructor===
new Base().constructor===
Base.prototype.constructor===
Base
...プロトタイプを変更しなかった最も基本的なオブジェクトまでずっと。
これを行うのは従来の方法ですか?
JavaScriptオブジェクト/クラスを扱う場合、1つの規則はありません。すべてのライブラリのメタクラスシステムの動作はわずかに異なります。各派生クラスに手動で「コンストラクター」を書き込むものは見たことがありませんが、実際のコンストラクターを実際に使用可能にしたい場合は、他のソリューションと同じくらい良い解決策のようです。また、「コンストラクタ」を提供しないブラウザ/エンジンとコードの互換性を確保します。
ただし、既存の異なる動作をする「コンストラクター」プロパティとの混乱を避けるため、別の名前を付けることを検討します。
他のヒント
オブジェクトがSubのインスタンスであるかどうかをテストする場合は、 instanceof
演算子を使用します:-
print(s instanceof Sub);
オブジェクトがSubのインスタンスであるか、Subのサブクラスのインスタンスであるかを知りたい場合は、 isPrototypeOf
メソッドを使用します:-
print(Sub.prototype.isPrototypeOf(s));
ええ、
Sub.prototype.constructor = Sub;
instanceofを使用しますが、より良い解決策があります。こちらをご覧ください: TDD JS継承GitHub で、 Parasitic Combination Inheritance パターン。コードはTDDであるため、非常に迅速にコードを理解し、名前を変更するだけで開始できます。これは基本的にYAHOO.lang.extendが使用するものです(出典:yahoo従業員および著者Nicholas ZakasのWeb開発者向けプロフェッショナルJavaScript、第2 ED、181ページ)。ちなみに良い本(とにかく提携していない!)
なぜですか?使用している古典的なパターンには静的参照変数があるため(ベースオブジェクトにvar arr = [1,2]を作成すると、すべてのインスタンスは読み取り/書き込みができ、「arr」の「状態を共有」します!コンストラクタースチールを使用すると、これを回避できます。例を参照してください。