最近、「JavaScript Advanced Programming」(第2版)を見ています
JavaScriptのオブジェクトの作成
•工場モード
•コンストラクターモード
•プロトタイプモード
•コンストラクターとプロトタイプパターンの組み合わせ
•プロトタイプの動的モード
ほとんどのオブジェクト指向言語には、同じ方法と属性を持つ複数のオブジェクトを作成できるクラスの概念があります。技術的には、JavaScriptはオブジェクト指向の言語ですが、JavaScriptにはクラスの概念がありませんが、すべてはオブジェクトです。任意のオブジェクトは特定の参照タイプのインスタンスであり、既存の参照タイプを介して作成されます。参照タイプは、ネイティブまたはカスタマイズできます。ネイティブリファレンスタイプは、オブジェクト、配列、データ、regexp、機能です。 !参照タイプは、通常クラスと呼ばれるデータと関数を整理するデータ構造です。クラスの概念がないJavaScriptでは、解決する必要がある問題は、オブジェクトを効率的に作成する方法です。
1.1.0。オブジェクトを作成するための一般的な方法
var person = {}; //オブジェクトリテラル表現は、var person = new objcect()に相当します。 person.name = 'evansdiy'; person.age = '22'; person.friends = ['ajiao'、 'tiantian'、 'pangzi']; person.logname = function(){console.log(this.name);}オブジェクト参照タイプに基づいて、オブジェクトが作成されます。オブジェクトには4つのプロパティが含まれており、そのうちの1つはメソッドです。人のような多くのインスタンスが必要な場合は、多くの重複コードがあります。
1.1.1。工場モード[トップ]
オブジェクトの詳細を含めることができる関数を持つオブジェクトを作成し、オブジェクトを返すことができます。
function person(name、age、friends){var o = {name:name、age、friends:friends、logname:function(){console.log(this.name); }}; return o;} var person1 = person( 'evansdiy'、 '22'、['ajiao'、 'tiantian'、 'pangzi']);個人関数が呼び出されるたびに、関数内のオブジェクトoを介して新しいオブジェクトが作成され、その後返されます。これとは別に、この内部オブジェクトoは、新しいオブジェクトを作成するために存在します。さらに、工場モードによって作成されたオブジェクトのタイプを決定することは不可能です。
1.1.2.構成モード[上]
function person(name、age、job){this.name = name; this.age = age; this.job = job; this.logname = function(){console.log(this.name); }} //新しいオペレーターvar person1 = new person( 'boy-a'、 '22'、 'worker'); var person2 = new person( 'girl-b'、 '23'、 'teacher'); person1.logname(); //boy-aperson2.logname(); // girl-a工場モードを比較すると、ここで中間オブジェクトを作成する必要がないことがわかります。リターンはありません。さらに、コンストラクターのインスタンスは、オブジェクト認識の問題を解決する特定のタイプとして識別できます(インスタンスのコンストラクター属性を確認するか、インスタンスを使用してインスタンスがコンストラクターによって作成されているかどうかを確認します)。
console.log(person1.constructor == person); //コンストラクターはコンストラクターのプロトタイプに配置され、コンストラクターをポイントし、結果は真です
console.log(person1 instance of person); // instance of operatorを使用して、person1がコンストラクターのインスタンスであるかどうかを判断しますが、コンストラクターパターンにも独自の問題があります。実際、LogNameメソッドは各インスタンスで1回再作成されます。インスタンス化によって作成された方法は等しくなく、次のコードがfalseになることに注意する必要があります。
console.log(person1.logname == person2.logname); // falseこの問題を解決するために、コンストラクターの外側(グローバル関数に変更)を移動できます。
function logname(){console.log(this.name);} function logage(){console.log(this.age);}ただし、グローバルに作成されたグローバルな機能は、人によって作成されたインスタンスによってのみ呼び出されますが、これは少し非現実的です。多くの方法がある場合、それらはまだ1つずつ定義する必要があり、カプセル化がありません。
1.1.3.プロトタイプモード[TOP]
JavaScriptの各関数には、プロトタイプ属性へのポインターが含まれています(ほとんどのブラウザは内部属性__Proto__を介してアクセスできます)。プロトタイプ属性は、特定の参照タイプによって作成されたすべてのインスタンスで共有されるプロパティとメソッドを含むオブジェクトです。
function person()person.name = 'evansdiy'; person.prototype.friends = ['ajiao'、 'jianjian'、 'pangzi']; person.prototype.logname = function(){console.log(this.name);} var person1 = new person上記のコードはこれらのことをします:
1。コンストラクターの人を定義します。人間関数は自動的にプロトタイププロパティを取得します。このプロパティには、デフォルトで人を指すコンストラクタープロパティのみが含まれています。
2. person.prototypeを介して3つの属性を追加します。そのうちの1つはメソッドとして使用されます。
3。人のインスタンスを作成し、インスタンスのlogname()メソッドを呼び出します。
ここで注意する必要があるのは、logname()メソッドの呼び出しプロセスです。
1。Person1インスタンスでlogname()メソッドを調べると、そのような方法がないことがわかりました。
2。Person1のプロトタイプでLOGAME()メソッドを探します1。この方法があります。したがって、このような検索プロセスに基づいてこの方法を呼び出します。インスタンスのプロトタイプの同性属性を定義することにより、インスタンスがプロトタイプの同名属性にアクセスするのを防ぐことができます。そうすることは、プロトタイプの同名属性を削除するのではなく、インスタンスがアクセスするのを防ぐだけであることに注意する必要があります。
var person2 = new Person();
person2.name = 'laocai';インスタンスでプロパティが不要になった場合は、削除演算子を介して削除できます。
delete person2.name; for-inループを使用して、インスタンスがアクセスできるすべての属性を列挙します(属性がインスタンスまたはプロトタイプに存在するかどうかに関係なく):
for(i in person1){console.log(i);}同時に、hasownProperty()メソッドを使用して、インスタンスまたはプロトタイプに特定のプロパティが存在するかどうかを判断することもできます。インスタンスにプロパティが存在する場合にのみ、TRUEが返されます。
console.log(person1.hasownproperty( 'name')); // true! HasownPropertyはオブジェクトのプロトタイプから来ており、JavaScriptでプロパティを処理する際にプロトタイプチェーンを調べない唯一の方法です。 [JavaScript Secret Gardenを介して]さらに、In OperatorおよびhasownProperty()メソッドを使用して、特定のプロパティがインスタンスまたはプロトタイプに存在するかどうかを判断することもできます。
console.log(( 'friends' in person1)&&!person1.hasownproperty( 'friends')));最初に、person1がfriendsプロパティにアクセスできるかどうかを判断します。可能であれば、このプロパティがインスタンスに存在するかどうかを判断します(前のものに注意してください!)。インスタンスに存在しない場合、このプロパティがプロトタイプに存在することを意味します。前述のように、プロトタイプはオブジェクトでもあるため、オブジェクトのリテラル表現を使用してプロトタイプを記述できます。プロトタイプにコードを追加する以前の執筆方法は、次のように変更できます。
person.prototype = {name: 'evansdiy'、friends:['ajiao'、 'jianjian'、 'pangzi']、logname:function(){console.log(this.name); }}オブジェクトリテラル構文はプロトタイププロトタイプ全体を書き直すため、コンストラクターを作成するときにデフォルトで取得されたコンストラクター属性は、オブジェクトコンストラクターを指します。
//オブジェクトの後、リテラルがプロトタイプを書き直します
console.log(person1.constructor); //オブジェクトただし、instance of演算子は引き続き希望の結果を返します。
//オブジェクトの後、リテラルがプロトタイプを書き直します
console.log(person1 instance of person); //もちろん、この問題を解決するためにプロトタイプのコンストラクター値を手動で設定できます。
person.prototype = {constructor:person、......}オブジェクトインスタンスが作成された後にプロトタイプオブジェクトが変更された場合、プロトタイプの変更はすべてのオブジェクトインスタンスにすぐに反映されます。
function person(){}; var person1 = new person(); person.prototype.name = 'evansdiy'; console.log(person1.name); // 'evansdiy' 'インスタンスとプロトタイプの間の接続は、プロトタイプのコピーではなく、単なるポインターです。プロトタイプは実際には検索プロセスです。プロトタイプオブジェクトに加えられた変更は、インスタンスの作成後にプロトタイプが変更された場合でも、すべてのオブジェクトインスタンスに反映されます。オブジェクトインスタンスを作成した後にプロトタイプオブジェクトが書き直された場合はどうなりますか?
function person(){}; var person1 = new person1(); //作成されたインスタンスは元のプロトタイプを指しますconsole.log(person1.friends);上記のコードは、最後の行に実行されると、未定義のエラーが発生します。 Person1のアクセス可能なプロパティを列挙するためにforinを使用すると、内部には何もないことがわかりますが、person2はプロトタイプの友人属性にアクセスできます。 !プロトタイプの書き換えは、既存のプロトタイプと以前に作成されたすべてのオブジェクトインスタンスとの間の接続を遮断します。以前に作成されたオブジェクトインスタンスのプロトタイプはまだそこにありますが、古いです。
// person1を作成するとき、プロトタイプオブジェクトはまだ書き直されていないため、プロトタイプオブジェクトのコンストラクターはまだデフォルトのwense()です。
console.log(person1.constructor); // person()
//しかし、person2のコンストラクターはobject()を指します
console.log(person2.constructor); // object()プロトタイプパターンはコンストラクターのパラメーターを渡すプロセスを無視し、すべてのインスタンスが同じ属性値を取得することに注意する必要があります。同時に、プロトタイプパターンには大きな問題があります。つまり、プロトタイプオブジェクトの参照型値はすべてのインスタンスで共有され、参照型値の変更もすべてのオブジェクトインスタンスに反映されます。
function person(){}; person.prototype = {friends:['ajiao'、 'tiantian'、 'pangzi']} var person1 = new person(); var person2 = new person(); person1.friends.push( 'laocai'); console.log(person2.friends);Person1 Friendsの参照タイプの値を変更すると、Person2の友人も変更されることを意味します。実際、プロトタイプで保存された友人は、実際にはヒープ内の友人の価値へのポインターにすぎません(このポインターの長さは固定され、スタックに保存されます)。インスタンスがプロトタイプを介して参照型値にアクセスすると、それぞれのインスタンスでコピーにアクセスする代わりに、ポインターによってもアクセスされます(そのようなコピーは存在しません)。
1.1.4。コンストラクターとプロトタイプパターンと組み合わせてオブジェクトを作成します[TOP]
コンストラクターとプロトタイプモードの利点を組み合わせて、それぞれの欠点を補い、コンストラクターを使用して初期化パラメーターを渡し、それらのインスタンス属性を定義し、プロトタイプを使用して一般的な方法とパブリック属性を定義します。このモードは最も広く使用されています。
function person(name、age){this.name = name; this.age = age; this.friends = ['ajiao'、 'jianjian'、 'pangzi'];} person.prototype = {constructor:person、logname:function(){console.log(this.name); }} var person1 = new person( 'evansdiy'、 '22'); var person2 = new person( 'amy'、 '21'); person1.logname(); // 'evansdiy'person1.friends.push(' haixao '); console.log(person2.friends.length); // 31.1.5.プロトタイプ動的モード[TOP]
プロトタイプの動的モードは、コンストラクターに必要なすべての情報をカプセル化し、IFステートメントを使用して、プロトタイプ内の特定のプロパティが存在するかどうかを判断します。それが存在しない場合(コンストラクターが初めて呼び出された場合)、IFステートメント内でプロトタイプ初期化コードを実行します。
function person(name、age){this.name = name; this.age = age; if(typeof this.logname!= 'function'){person.prototype.logname = function(){console.log(this.name); }; person.prototype.logage = function(){console.log(this.age); }; }; };} var person1 = new person( 'evansdiy'、 '22'); //コンストラクターが初めて呼び出され、この時点でプロトタイプが変更されました。 var person2 = new person( 'amy'、 '21'); // logname()メソッドはすでに存在し、プロトタイプは再び変更されませんこのパターンは、オブジェクトリテラル構文を使用してプロトタイプオブジェクトを書き込むことができないことに注意してください(これにより、プロトタイプオブジェクトがオーバーライドされます)。プロトタイプが書き換えられている場合、コンストラクターによって作成された最初のインスタンスにアクセスできるプロトタイプオブジェクトは、IFステートメントにプロトタイプオブジェクトプロパティを含めません。
function person(name、age){this.name = name; this.age = age; if(typeof this.logname!= 'function'){person.prototype = {logname:function(){console.log(this.name); }、logage:function(){console.log(this.age); }}}}各モデルには独自のアプリケーションシナリオがあることに注意してください。その利点と短所は関係ありません。
JavaScriptでオブジェクトを作成するさまざまなモードの上記の簡単な分析は、私があなたと共有するすべてのコンテンツです。私はそれがあなたに参照を与えることができることを願っています、そしてあなたがwulin.comをもっとサポートできることを願っています。