ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript の難しさ: プロトタイプとコンストラクターのバインディング例の詳細な説明

JavaScript の難しさ: プロトタイプとコンストラクターのバインディング例の詳細な説明

伊谢尔伦
伊谢尔伦オリジナル
2017-07-20 15:37:561501ブラウズ

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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。