前々回の記事では、JavaScriptにおけるプロトタイプのメモリモデルと、プロトタイプの書き換え方法、つまり注意点について紹介しました。プロトタイプを理解したら、プロトタイプを通じて JavaScript オブジェクトを作成できます。プロトタイプベースの作成方法はカプセル化を効果的に完了できますが、まだいくつかの問題があります。
プロトタイプを介してオブジェクトを作成すると、主に 2 つの問題が発生します:
1. オブジェクトの属性値をコンストラクターを介して設定することはできません。
2. 属性に参照型の変数がある場合、変数の値が重複する可能性があります。
次の例を見てみましょう:
function Person(){} Person.prototype = { constructor:Person, name:"Leon", age:22, friends:["Ada","Chris"], say:function(){ console.info(this.name+"["+this.friends+"]"); } }
上記のコードでは、Person クラスを作成し、プロトタイプのオーバーライドを通じていくつかのプロパティとメソッドを設定しました。これは参照の配列です。種類。次に、Person クラスを使用してオブジェクトを作成します。コードは次のとおりです。
var p1 = new Person(); p1.name = "John"; p1.say(); //控制台输出:Jhon[Ada,Chris]
Object クラスを使用してオブジェクト p1 を作成します。プロトタイプ メソッドを使用してオブジェクトを作成する場合、オブジェクト p1 に属性を設定する方法がないことがわかります。オブジェクトの作成後にのみ設定します。次に、p1 のsay() メソッドを呼び出すと、コンソールには Jhon[Ada, Chris] が出力されます。この時点まではすべて正常です。
その後、オブジェクト p1 に新しい友達を追加すると、問題が発生します。コードは以下の通りです:
p1.friends.push("Mike"); //为p1增加一个朋友(注意这里是在原型中添加) p1.say();
配列のpushメソッドでp1に新しい友達「Mike」を追加します。このとき、オブジェクトp1自身の空間にはfriends属性が存在しないので、「Mike」が追加されます。
新しく追加された配列要素はプロトタイプに配置されるため、この時点でオブジェクト p2 を作成すると、後で作成されるすべてのオブジェクトがこの属性を共有します。彼の友達には「マイク」もいます。これは私たちが見たくない結果です。
var p2 = new Person(); //如果p1 push之后,原型中就多了一个人,p2也多了一个朋友 p2.say();
プロトタイプとコンストラクターの組み合わせに基づいてオブジェクトを作成する
上記の問題を解決するには、プロトタイプとコンストラクターの組み合わせに基づいてオブジェクトを作成できます。つまり、プロパティはコンストラクターで定義され、メソッドはプロトタイプで定義されます。この方法は両方の利点を効果的に組み合わせたもので、JavaScript でオブジェクトを作成するために最も一般的に使用される方法です。
function Person(name,age,friends){ //属性在构造函数中定义 this.name = name; this.age = age; this.friends = friends; } Person.prototype = { //方法在原型中定义 constructor:Person, say:function(){ console.info(this.name+"["+this.friends+"]"); } }
この方法で作成されたオブジェクトの場合、すべてのプロパティはオブジェクト独自の空間に保存されます。この時点で、オブジェクトを作成するときに、オブジェクトに独自のプロパティを設定できます。
var p1 = new Person("Leon",22,["Ada","Chris"]); p1.name = "John"; p1.say(); //控制台输出: John[Ada,Chris]
上記のコードを完了すると、 Person クラスと p1 オブジェクトのメモリ モデルは次のようになります。
このとき、オブジェクト p1 に新しい友達を追加すると、それは p1 に追加されます。オブジェクト自身のメモリ空間 friends 属性に追加されます。このように、各オブジェクトのプロパティは独立しており、互いに干渉しません。
p1.friends.push("Mike"); //为p1增加一个朋友(注意这里是在p1自己的空间中添加) p1.say(); //控制台输出: John[Ada,Chris,Mike] var p2 = new Person(); p2.say(); //控制台输出: John[Ada,Chris]
したがって、今オブジェクト p2 が作成されると、p2 オブジェクトの友達は「Ada」と「Chris」のみになり、「Mike」は含まれません。
動的プロトタイピングを使用したオブジェクトの作成
プロトタイプとコンストラクターの組み合わせに基づいてオブジェクトを作成するのは完璧ですが、純粋なオブジェクト指向言語でオブジェクトを作成する方法との間には、まだいくつかの違いがあります。クラスメソッドは内部で定義されます。外のクラス。定義オブジェクトをオブジェクト指向仕様の要件にさらに適合させるために、定義メソッドのプロトタイプ コードを Person コンストラクターに配置できます。このオブジェクトを作成する方法はダイナミック プロトタイピングと呼ばれます。
// 动态原型方式 function Person(name,age,friends){ this.name = name; this.age = age; this.friends = friends; Person.prototype.say = function(){ console.info(this.name+"["+this.friends+"]"); } }
動的プロトタイピングを使用してオブジェクトを作成する場合、メソッドを定義するときにプロトタイプの書き換えを使用できないことに注意してください:
// 错误的动态原型方式 function Person(name,age,friends){ this.name = name; this.age = age; this.friends = friends; //不能使用原型重写的方式来设置方法 Person.prototype = { constructor:Person, say:function(){ console.info(this.name+"["+this.friends+"]"); } } }
動的プロトタイピングを使用してオブジェクトを作成すると、クラス内のメソッドにも問題が発生します。は Person.prototype.say を通じて作成されるため、オブジェクトが作成されるたびに、新しい Say() メソッドがメモリ内に作成されます。この問題を解決するには、まず Person.prototype.say メソッドが存在するかどうかを判断し、存在しない場合のみ作成し、存在しない場合は作成しません。
// 动态原型方式 function Person(name,age,friends){ this.name = name; this.age = age; this.friends = friends; //判断Person.prototype.say是否存在,不存在就创建 if(!Person.prototype.say){ alert("创建say方法"); Person.prototype.say = function(){ console.info(this.name+"["+this.friends+"]"); } } }
为了验证判断条件是否起作用,我们在代码中的判断分支中添加了一个弹出对话框语句。我们可以创建2个对象,然后2个对象分别调用say()方法,在结果中,第一个对象在调用say()方法时会弹出对话框,而第二个对象在调用say()方法时就不会在弹出对话框了,也就是说创建第二个对象时不会再添加say()方法。
以上就是JavaScript面向对象-基于组合和动态原型创建对象的内容,更多相关内容请关注PHP中文网(www.php.cn)!