JavaScript オブジェクトとコンストラクター
JavaScript オブジェクトの定義は次のように定義できます
var a = { x : 1, y : 2, add : function () { return this.x + this.y; }, mul : function () { return this.x * this.y; } }
この方法では、2 つのパブリック メンバー x と y に加えて、この変数には次の変数もあります。 2 つの add 関数と mul 関数 (パブリック メソッド)。ただし、この定義方法には 2 つの欠点があります:
1. var b=a; とすると、b のメンバーを変更するたびに、a のメンバーも変更されることになります。 JavaScript 参照のため
2. オブジェクトを生成するたびに一部のメンバーをカスタマイズする必要がある場合は、対応する代入操作を記述し、コードの行数を増やす必要があります。
したがって、JavaScript オブジェクトを定義する前に、まずコンストラクターを定義できます。
function A(x, y) { this.x = x; this.y = y; this.add = function () { return this.x + this.y; } this.mul = function () { return this.x * this.y; } }
次に、オブジェクトを定義します
a = new A(1, 2);
上記のコードは単純そうですが、C++などのオブジェクト指向言語とは区別する必要があります。 Aは「クラス」という概念ではありません。厳密な意味では、JavaScript にはクラスがないため、コンストラクターを呼び出すだけです。
ここで問題は、継承をどのように実装するかということです。 C++ は、カプセル化、継承、ポリモーフィズムという 3 つのオブジェクト指向機能を明確に実装しています。ただし、JavaScript のような比較的大まかな言語の場合、厳密な継承メカニズムはなく、代わりに次のメソッドがそれをシミュレートするために使用されます。
JavaScript プロトタイプ
後で apply 関数や call 関数を説明するために、ここで最初にプロトタイプを紹介します。プロトタイプは Function でのみ使用できます。
継承を有効に活用するには、まず継承がなぜ設計されているのかを理解する必要があります。コードの再利用を実現するには「共通部分を抽出する」ことに他なりません。
つまり、JavaScriptでは、公開部分もFunctionのプロトタイプに配置されます。
プロトタイプを使用して継承を実装する 2 つの例を比較してみましょう
function A(x, y) { this.x = x; this.y = y; this.add = function () { return this.x + this.y; } this.mul = function () { return this.x * this.y; } } function B(x,y){ } B.prototype=new A(1,2); console.log(new B(3,4).add()); //3
この例では、サブクラスのプロトタイプはクラス A オブジェクトを指します
B が A を継承する別の例を実装してみましょう:
function A() { } A.prototype = { x : 1, y : 2, add : function () { return this.x + this.y; }, mul : function () { return this.x * this.y; } } A.prototype.constructor=A; function B(){ } B.prototype=A.prototype; B.prototype.constructor=B;
B のプロトタイプ オブジェクトは A のプロトタイプ オブジェクトを参照します。これは参照であるため、B のプロトタイプ オブジェクトが変更されると、A のプロトタイプ オブジェクトも変更されます。これは、本質的にすべてがメモリの一部を指しているためです。したがって、タイプ B のプロトタイプを変更するたびに、混乱を避けるためにコンストラクターを手動で元に戻す必要があります。 2 つの例と比較すると、前の例では参照がないため、この問題は発生しません。
型 B のオブジェクトを作成します
b=new B();
b オブジェクトには、型 A のすべてのメンバーが含まれています
console.log(b.add()); //3
すべてのプロトタイプ オブジェクトには、constructor と _proto_ という 2 つの重要なメンバーがあるため、constructor は本質的に関数ポインターです。したがって、B.prototype=A.prototype が実行された後、コンストラクターは上書きされるため、後でコンストラクターを型 B のコンストラクターにリダイレクトする必要があります。
JavaScript コンストラクターのバインディング
型 A のコンストラクターを定義した後、型 B を定義し、型 B のコンストラクター内に型 A のコンストラクターを「埋め込み実行」します。
function A(x, y) { this.x = x; this.y = y; this.add = function () { return this.x + this.y; } this.mul = function () { return this.x * this.y; } } function B(x, y, z) { A.apply(this, arguments); this.z = z; } console.log(new B(1,2,3));
apply関数は基本的にcall関数と同じで、A型コンストラクターはB型コンストラクター内で実行できます。同時に、A のすべてのメンバーを継承することもできます。
表示結果:
ここに数式があります: B コンストラクターに A.apply(this) を書き、B によって構築されたオブジェクトが A コンストラクター内のすべてのメンバーを持つことができるようにします。
applyとcallと言えば多重継承も実現できます
function IA(){ this.walk=function(){ console.log("walk"); } } function IB(){ this.run=function(){ console.log("run"); } } function Person(){ IA.apply(this); IB.apply(this); } var p=new Person(); p.walk(); //walk p.run(); //run
以上がJavaScript の難しさ: プロトタイプとコンストラクターのバインディング例の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。