ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScript のオブジェクト指向とプロトタイプ関数の詳細な分析_JavaScript スキル

JavaScript のオブジェクト指向とプロトタイプ関数の詳細な分析_JavaScript スキル

WBOY
リリース: 2016-05-16 15:16:00
オリジナル
1239 人が閲覧しました

オブジェクトは JavaScript において非常に重要な要素です。オブジェクトを完全に理解できるかどうかは、JavaScript システム全体の基本的な理解に直接関係します。端的に言えば、JavaScript はオブジェクトの集まりです。 。 (ビープ!)。

以下では、一般的に使用されるオブジェクト作成モードをいくつか紹介します

新しいキーワードを使用して作成

オブジェクト作成の最も基本的な方法は、他のほとんどの言語と同じです。オブジェクトは存在しないので、新しいオブジェクトを作成します。

var gf = new Object(); gf.name = "tangwei"; gf.bar = "c++"; gf.sayWhat = function() { console.log(this.name + "said:love you forever"); }
ログイン後にコピー

リテラルを使用して作成

これは適切だと思われますが、変数を定義するこのような複雑で控えめな方法がオタクに好まれるのでしょうか? スクリプト言語として、他の言語と同じスタイルを持つ必要があるため、オブジェクト リテラルの定義方法が登場しました:

var gf = { name : "tangwei", bar : "c++", sayWhat : function() { console.log(this.name + "said:love you forever"); } }
ログイン後にコピー

工場出荷時モード

実際、これはオブジェクトを定義するために実際に最も一般的に使用される方法ですが、同様のプロパティを持つオブジェクトを多数持ちたいと考えています (考えるのはとても楽しいです...) どうすればよいでしょうか?それらを 1 つずつ定義すると、大量のコードが生成されることになるため、ファクトリを構築してオブジェクトをバッチで生成してみてはいかがでしょうか。したがって、JavaScript の世界初のインフレータブル ベイビーが誕生します。 。 。いいえ、「ファクトリーモデル」が誕生しました!

function createGf(name, bar) { var o = new Object(); o.name = name; o.bar = bar; o.sayWhat = function() { alert(this.name + "said:love you forever"); } return o; } var gf1 = createGf("bingbing","d"); var gf2 = createGf("mimi","a");
ログイン後にコピー

コンストラクター

ファクトリ パターンは、複数の同様のオブジェクトを作成する問題を解決しますが、これらのオブジェクトはすべてオブジェクトから作成されるという問題が再び発生します。現時点では、別のモード、コンストラクター モードに切り替える必要があります:

function Gf(name,bar){ this.name = name; this.bar = bar; this.sayWhat = function(){ alert(this.name + "said:love you forever"); } } var gf1 = new Gf("vivian","f"); var gf2 = new Gf("vivian2","f");
ログイン後にコピー

ここでは、上の例の createGf を置き換えるために大文字で始まるコンストラクターを使用します。規則に従って、コンストラクターの最初の文字は大文字にする必要があることに注意してください。ここでは、新しいオブジェクトを作成し、コンストラクターのスコープを新しいオブジェクトに割り当て、コンストラクター内のメソッドを呼び出します。

上記のメソッドには何の問題もないように見えますが、2 つのインスタンスで呼び出されるコンストラクター内のsayWhat メソッドが同じ Function インスタンスではないことがわかります:

console.log(gf1.sayWhat == gf2.sayWhat); //false
ログイン後にコピー

同じメソッドを呼び出しても、異なるインスタンスを宣言するのはリソースの無駄です。コンストラクターの外側で、sayWhat 関数を最適化して宣言できます:

function Gf(name,bar){ this.name = name; this.bar = bar; this.sayWhat = sayWhat } function sayWhat(){ alert(this.name + "said:love you forever"); }
ログイン後にコピー

これにより、複数のインスタンスが同じメソッド インスタンスを複数回定義する問題は解決されますが、定義したsayWhat はグローバル スコープ メソッドですが、このメソッドを直接呼び出すことはできません。これは少し矛盾しています。特定のカプセル化プロパティを持つオブジェクトをよりエレガントに定義するにはどうすればよいでしょうか? JavaScript プロトタイプ オブジェクト パターンを見てみましょう。

プロトタイプ オブジェクト パターン

プロトタイプ オブジェクトを理解する

関数を作成すると、その関数には、コンストラクターを通じて作成された関数のプロトタイプ オブジェクトを指すプロトタイプ属性が含まれます。平たく言えば、プロトタイプ オブジェクトは、他のオブジェクトに共有プロパティとメソッドを提供するメモリ内のオブジェクトです。

プロトタイプ モードでは、コンストラクターでインスタンス属性を定義する必要はなく、属性情報をプロトタイプ オブジェクトに直接割り当てることができます。

function Gf(){ Gf.prototype.name = "vivian"; Gf.prototype.bar = "c++"; Gf.prototype.sayWhat = function(){ alert(this.name + "said:love you forever"); } } var gf1 = new Gf(); gf1.sayWhat(); var gf2 = new Gf();
ログイン後にコピー

コンストラクターとの違いは、ここでの新しいオブジェクトのプロパティとメソッドがすべてのインスタンスで共有できることです。つまり、gf1 と gf2 は同じプロパティとメソッドにアクセスします。プロトタイプ オブジェクトに割り当てる属性に加えて、いくつかの組み込み属性もあります。すべてのプロトタイプ オブジェクトには、プロトタイプ属性を含む関数へのポインターであるコンストラクター属性があります (さらに詳しく説明します)。この舌を巻くプロセスを写真でわかりやすく理解してみましょう:

すべてのオブジェクトにはプロトタイプ オブジェクト (プロトタイプ) があります。プロトタイプ オブジェクトには、プロトタイプ属性を含む関数を指すコンストラクター属性があります。Gf インスタンス gf1 と gf2 には両方とも、プロトタイプ オブジェクトを指す内部属性が含まれています (Firefox ブラウザーで表示)。はプライベート プロパティ プロトです)、オブジェクト内のプロパティにアクセスするときは、まずそのプロパティがインスタンス オブジェクトに存在するかどうかを尋ね、存在しない場合はプロトタイプ オブジェクトを探し続けます。

プロトタイプ オブジェクトを使用する

前の例では、プロトタイプ オブジェクトに属性を追加するときに、各オブジェクトに Gf.prototype を追加する必要があることがわかりました。上記のオブジェクト作成モードでは、リテラルを使用できることがわかりました。オブジェクトを作成します。ここで改善することもできます:

function Gf(){} Gf.prototype = { name : "vivian", bar : "c++", sayWhat : function(){ alert(this.name + "said:love you forever"); } }

ログイン後にコピー

ここで特別な注意が必要な点が 1 つあります。関数が定義されるたびに、このオブジェクトも同時にプロトタイプ オブジェクトが作成されるため、コンストラクター属性はオブジェクト Gf を指さなくなりました。新しいコンストラクター属性を取得します。これは、Gf.prototype を使用して元のプロトタイプ オブジェクトを本質的に上書きするため、コンストラクターは新しいオブジェクトのコンストラクター プロパティになり、Gf ではなく Object:

を指します。
var gf1 = new Gf(); console.log(gf1.constructor == Gf);//false console.log(gf1.constructor == Object)//true
ログイン後にコピー

一般情况下,这个微妙的改变是不会对我们造成影响的,但如果你对constructor有特殊的需求,我们也可以显式的指定下Gf.prototype的constructor属性:

Gf.prototype = { constructor : Gf, name : "vivian", bar : "c++", sayWhat : function() { alert(this.name + "said:love you forever"); } } var gf1 = new Gf(); console.log(gf1.constructor == Gf);//true
ログイン後にコピー

通过对原型对象模式的初步了解,我们发现所有的实例对象都共享相同的属性,这是原型模式的基本特点,但往往对于开发者来说这是把“双刃剑”,在实际开发中,我们希望的实例应该是具备自己的属性,这也是在实际开发中很少有人单独使用原型模式的主要原因。

构造函数和原型组合模式

在实际开发中,我们可以使用构造函数来定义对象的属性,使用原型来定义共享的属性和方法,这样我们就可以传递不同的参数来创建出不同的对象,同时又拥有了共享的方法和属性。

function Gf(name,bar){ this.name = name; this.bar = bar; } Gf.prototype = { constructor : Gf, sayWhat : function() { alert(this.name + "said:love you forever"); } } var gf1 = new Gf("vivian", "f"); var gf2 = new Gf("vivian1", "c");
ログイン後にコピー

在这个例子中,我们再构造函数中定义了对象各自的属性值,在原型对象中定义了constructor属性和sayWhat函数,这样gf1和gf2属性之间就不会产生影响了。这种模式也是实际开发中最常用的对象定义方式,包括很多JS库(bootstrap等)默认的采用的模式。

以上所述是小编给大家介绍的JavaScript面向对象和原型函数,希望对大家有所帮助。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート