JavaScript を使用したことがある学生はプロトタイプに精通しているはずですが、初心者は関数にプロトタイプ属性があることと、インスタンスにアクセスするための関数を追加できることだけを知っていて、その他のことはよくわかりません。高度な JavaScript プログラミングが解明され、ついにその謎が明らかになりました。
各関数には、オブジェクトへの参照であるプロトタイプ属性があります。このオブジェクトはプロトタイプ オブジェクトと呼ばれます。プロトタイプ オブジェクトには、関数インスタンスによって共有されるメソッドとプロパティが含まれます。つまり、関数はコンストラクター呼び出しとして使用されます。 new オペレーターが呼び出されると、新しく作成されたオブジェクトはプロトタイプ オブジェクトからプロパティとメソッドを継承します。
プライベート変数と関数
プロトタイプについて詳しく話す前に、プロトタイプの設計意図をよりよく理解できるように、いくつかの関連する事柄について話しましょう。以前に書いた JavaScript 名前空間の記事では、関数内で定義された変数や関数が外部へのインターフェイスを提供しない場合、外部からアクセスできなくなります。つまり、プライベート変数になります。そしてプライベートな機能。
function Obj(){ var a=0; //私有变量 var fn=function(){ //私有函数 } }
このように、変数 a と関数 fn は関数オブジェクト Obj の外部からアクセスすることはできません。これらはプライベートになり、関数 Obj のインスタンスであってもこれらの変数と関数にアクセスすることはできません
var o=new Obj(); console.log(o.a); //undefined console.log(o.fn); //undefined
静的変数。 , 関数
関数が定義されている場合、「.」によって追加された属性と関数にはオブジェクト自体からアクセスできますが、そのような変数と関数はそれぞれ静的変数と静的関数と呼ばれます。 , Java と C# を使用したことのある学生は、静的の意味を簡単に理解できます。
function Obj(){ } Obj.a=0; //静态变量 Obj.fn=function(){ //静态函数 } console.log(Obj.a); //0 console.log(typeof Obj.fn); //function var o=new Obj(); console.log(o.a); //undefined console.log(typeof o.fn); //undefined
インスタンス変数と関数
オブジェクト指向プログラミングでは、いくつかのライブラリ関数に加えて、オブジェクトの定義時にいくつかのプロパティとメソッドを定義することが望まれます。これらはインスタンス化後にアクセスできます
。function Obj(){ this.a=[]; //实例变量 this.fn=function(){ //实例方法 } } console.log(typeof Obj.a); //undefined console.log(typeof Obj.fn); //undefined var o=new Obj(); console.log(typeof o.a); //object console.log(typeof o.fn); //function
これは問題ありません。上記の目的を達成するには、
function Obj(){ this.a=[]; //实例变量 this.fn=function(){ //实例方法 } } var o1=new Obj(); o1.a.push(1); o1.fn={}; console.log(o1.a); //[1] console.log(typeof o1.fn); //object var o2=new Obj(); console.log(o2.a); //[] console.log(typeof o2.fn); //function
上記のコードの実行結果は完全に期待どおりですが、o1 では a と fn が変更されているのに、o2 では変更がないという問題も示しています。配列と関数は両方ともオブジェクトであるため、型は参照です。つまり、o1 のプロパティとメソッドと o2 のプロパティとメソッドは同じ名前ですが、それらは参照ではなく、プロパティとメソッドのコピーです。 Obj オブジェクトによって定義されます。
これは属性の問題ではありませんが、メソッドにとっては大きな問題です。メソッドはまったく同じ機能を実行しますが、関数オブジェクトに数千のインスタンス メソッドがある場合、その各インスタンスにはコピーが 2 つ存在するためです。何千ものメソッドのコピーを維持しなければならないのですが、これは明らかに非科学的です。プロトタイプが誕生しました。
prototype
新しい関数が作成されるたびに、特定のルールに従ってその関数のプロトタイプ属性が作成されます。デフォルトでは、プロトタイプ属性はコンストラクター (constructor) 属性を取得します。プロトタイプ属性が配置されている関数へのポインター コードを書いて上の図を見てください。
function Person(){ }
上の図からわかるように、Person オブジェクトは、prototype 属性を自動的に取得します。また、prototype もオブジェクトであり、Person オブジェクトを指すコンストラクター属性を自動的に取得します。
インスタンスを作成するためにコンストラクターが呼び出されるとき、インスタンスにはコンストラクターのプロトタイプを指す内部ポインター (多くのブラウザーではこのポインターは __proto__ という名前) が含まれます。この接続はインスタンスとコンストラクターのプロトタイプの間に存在します。インスタンスとコンストラクターの間ではありません。
function Person(name){ this.name=name; } Person.prototype.printName=function(){ alert(this.name); } var person1=new Person('Byron'); var person2=new Person('Frank');
person インスタンス person1 には name 属性が含まれており、自動的に Person のプロトタイプを指す __proto__ 属性が生成されます。プロトタイプに定義されている printName メソッドにアクセスできます。これはおそらく次のようなものです
プログラムのテストを書いてみましょう。プロトタイプのプロパティとメソッドを見て、それらが共有できるかどうかを確認してください
function Person(name){ this.name=name; } Person.prototype.share=[]; Person.prototype.printName=function(){ alert(this.name); } var person1=new Person('Byron'); var person2=new Person('Frank'); person1.share.push(1); person2.share.push(2); console.log(person2.share); //[1,2]
予想通りです!実際、コードはオブジェクトの属性を読み取るときに、指定された名前の属性から検索を実行します。その属性がインスタンス内で見つかった場合、その属性が検索されます。そうでない場合は、プロトタイプが検索され、まだ見つからない場合は、再帰後にオブジェクトが見つからない場合は、プロトタイプのプロトタイプ・オブジェクトを再帰し続けます。同様に、インスタンスにプロトタイプと同名のプロパティや関数が定義されている場合、プロトタイプのプロパティや関数は上書きされます。
function Person(name){ this.name=name; } Person.prototype.share=[]; var person=new Person('Byron'); person.share=0; console.log(person.share); //0而不是prototype中的[]
単純なオブジェクトを構築する
もちろん、プロトタイプは上記の問題を解決するために特別に定義されているわけではありませんが、上記の問題を解決します。この知識を理解すると、インスタンス オブジェクトのプロパティや関数が必要な場合は、プロトタイプで定義し、各インスタンスに個別のプロパティやメソッドを持たせたい場合は、これをインスタンス化して定義します。パラメータはコンストラクタを介して渡すことができます。
function Person(name){ this.name=name; } Person.prototype.share=[]; Person.prototype.printName=function(){ alert(this.name); }
JavaScript プロトタイプの使用法に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。