最初は、明確な説明を求めずに丸呑みしたので、突然悟ったような気分になりましたが、夜寝るときに、すぐに読んだ後、多くの問題を発見し、何も理解できませんでした。時は、こんな感じだったことが分かりました。数日使ってみて、手書きではまだ記憶に頼っていることがわかったので、次回、また次回…
記憶だけで物事を理解するのは当てにならないので、そして長い時間が経つと頭が真っ白になってしまいます。特に多くの技術的な考え方や原則は、実践しなければ、その時はしっかりと考えていても、時間が経つと忘れてしまいます。さらに、インターネット上にあるものは、単にそれらを閲覧するための便利な方法を提供しているとしか言えません。結局のところ、それらのほとんどは個人的な要約であり、明確に説明するのが難しいものもあります。は同じことを話していますが、一般的にはステップと章が異なるため、交差記憶が増えれば増えるほど混乱が生じます。懐疑的な態度で物事を見てみると、それがどのようなものであるかがわかります。高品質が保証されている本や公式のものは良い情報源です。
今はまだはっきりと目が見え、頭がまだはっきりしているうちに、それを記録してメモしてください。概念的なものは、将来の誤解を減らすために本に記載されています。例を手書きで書いて検証し、後で一目で理解できるように絵を描きます。
1. カプセル化
オブジェクト定義: ECMA-262 ではオブジェクトを次のように定義しています。「属性には基本的な値、オブジェクト、または関数を含めることができます」 。
オブジェクトの作成: 各オブジェクトは参照型に基づいて作成されます。この参照型は、ネイティブ型 (Object、Array、Date、RegExp、Function、Boolean、Number、String) または自己定義型にすることができます。 。
1. コンストラクター パターン
this.name = 名前;
this.sayName = function() {
alert(this.name); >}
}
オブジェクト インスタンスは、上記のコンストラクターを通じて new 演算子を使用して作成できます。
var zhangsan = 新しい人('zhangsan', 20);
var lisi = 新しい人('lisi', 20);
zhangsan.sayName();//zhangsan
lisi.sayName (); //lisi
new によるオブジェクトの作成は 4 つのステップを経ます
1. 新しいオブジェクトを作成します。
2. コンストラクターのスコープを新しいオブジェクトに割り当てます (つまり、this は新しいオブジェクトを指します) [Person のオリジナルの this は window を指します]
3. 実行します。コンストラクター内のコード (この新しいオブジェクトに属性を追加します);
4. 新しいオブジェクトを返します。
コードを使用して新規復元する手順:
コードをコピー
P.prototype.constructor = P;
P.apply(o, args)
新しいインスタンス作成メソッドをテストします
var wangwu = createperson(person, 'wangwu' , 20) ;
wangwu.sayName();//wangwu
2. プロトタイプ モード
プロトタイプ オブジェクトの概念: 新しい関数を作成するたびに、この属性は、関数のプロトタイプ オブジェクトを指します。デフォルトでは、すべてのプロトタイプ オブジェクトは、プロトタイプ プロパティが配置されている関数へのポインターを含むコンストラクター プロパティを自動的に取得します。このコンストラクターを通じて、プロトタイプ オブジェクトに他のプロパティやメソッドを追加し続けることができます。カスタム コンストラクターを作成した後、そのプロトタイプ オブジェクトはデフォルトでコンストラクター プロパティのみを取得します。他のメソッドは Object から継承されます。新しいインスタンスを作成するためにコンストラクターが呼び出されるとき、インスタンスにはコンストラクターのプロトタイプ オブジェクトを指すポインター (内部プロパティ) が含まれます。 ECMA-262 第 5 版では、このポインターを [[プロトタイプ]] と呼びます。スクリプトで [[Prototype]] にアクセスする標準的な方法はありませんが、Firefox、Safari、Chrome は他の実装のすべてのオブジェクトで __proto__ 属性をサポートしており、この属性はスクリプトにはまったく表示されません。ただし、明確にしておくべき本当に重要な点は、接続はインスタンスとコンストラクターの間ではなく、インスタンスとコンストラクターのプロトタイプ オブジェクトの間に存在するということです。
この段落では、基本的にコンストラクター、プロトタイプ、および例の関係を概説します。次の図は、それをより明確に示しています。
コードをコピーします。
コードは次のとおりです:
関数 人(名前, 年齢) {
この.名前 = 名前;
この.年齢 = 年齢;
人.prototype.country = '中国語'; 🎜>person.prototype.say Country = function() {
alert(this.country);
}
var zhangsan = new Person('zhangsan', 20); = 新しい人 ('lisi', 20);
zhangsan.say Country() //中国語
lisi.say Country(); //中国語
alert( = lisi.say Country); //true
注: コンストラクターのプロトタイプ オブジェクトは主に、複数のオブジェクト インスタンスがそれに含まれるプロパティとメソッドを共有できるようにするために使用されます。ただし、これは問題が発生しやすい場所でもあります。プロトタイプ オブジェクトに参照型が含まれる場合、その参照型にはポインターが格納されるため、値の共有が発生します。次のように:
コードをコピー
コードは次のとおりです: person.prototype.friends = ['wangwu' ]; //人は配列型を追加します
zhangsan.friends.push('zhaoliu'); //Zhang San の変更は Li Si
alert(zhangsan.friends); に影響します。 zhaoliu
alert(lisi.friends); //wangwu, zhaoliu Li Si にはもう 1 つあります
3. コンストラクター モードとプロトタイプ モードを組み合わせて使用します
カスタム タイプを作成するために最も広く普及し認知されている方法を使用することです。コンストラクター パターンはインスタンス プロパティの定義に使用され、プロトタイプ パターンはメソッドと共有プロパティの定義に使用されます。このようにして、各インスタンスはインスタンス属性の独自のコピーを持ち、メソッドへの参照を共有するため、メモリが最大限に節約されます。
変更されたプロトタイプ モードは次のとおりです:
この.名前 = 名前;
この.年齢 = 年齢;
この.友達 = ['王武']; 🎜>
person.prototype.country = 'chinese';
person.prototype.say Country = function() {
alert(this.country)
var zhangsan; = 新しい人 (' zhangsan', 20);
var lisi = 新しい人 ('lisi', 20);
zhangsan.friends.push('zhaoliu'); .friends); / /wangwu,zhaoliu
alert(lisi.friends); //wangwu
継承の基本概念ECMAScript は主にプロトタイプ チェーンの継承に依存します (プロパティをコピーして継承することもできます)。
プロトタイプ チェーンの基本的な考え方は、プロトタイプを使用して、ある参照型に別の参照型のプロパティとメソッドを継承させることです。コンストラクター、プロトタイプ、およびサンプルの関係は次のとおりです。各コンストラクターにはプロトタイプ オブジェクトがあり、プロトタイプ オブジェクトにはコンストラクターへのポインターが含まれ、インスタンスにはプロトタイプへの内部ポインターが含まれます。したがって、プロトタイプ オブジェクトを別の型のインスタンスと等しくすると、プロトタイプ オブジェクトには他のプロトタイプへのポインタが含まれることになり、したがって、他のプロトタイプにも他のコンストラクタへのこのポインタが含まれることになります。別のプロトタイプが別のタイプのインスタンスである場合、上記の関係は依然として保持され、以下同様に層ごとに、インスタンスとプロトタイプのチェーンが形成されます。これがプロトタイプチェーンの基本概念です。
読みにくく、理解するのが難しいです。例を通して直接検証してください。
1. プロトタイプチェーンの継承
コードをコピーします
コードは次のとおりです:
function Parent() {
this.pname = 'parent';
Parent.prototype.getParentName = function() {
return this.pname; function Child() { this.cname = 'child'; } //子コンストラクターのプロトタイプは親コンストラクターのインスタンスに設定され、子が次のようにプロトタイプ チェーンを形成します。 getParentName メソッド Child .prototype = new Parent();
Child.prototype.getChildName = function() {
return this.cname>}
var c = new Child();
alert(c.getParentName()); //親
図:
プロトタイプチェーンの問題。親クラスに参照型が含まれている場合、Child.prototype = new Parent() は親クラスの参照型を次のようにします。サブクラスのプロトタイプ、参照型値のプロトタイププロパティはすべてのインスタンスで共有されます。問題はセクション [1、2] に戻ります。
2. 組み合わせ継承 - 最も一般的に使用される継承方法
組み合わせ継承は、プロトタイプ チェーンと借用したコンストラクター (適用、呼び出し) テクノロジーの組み合わせです。このアイデアは、プロトタイプ チェーンを使用してプロトタイプのプロパティとメソッドの継承を実現し、コンストラクターを借用してインスタンス プロパティの継承を実現することです。このようにして、プロトタイプ上でメソッドを定義して関数の再利用を実現し、各インスタンスが独自の属性を持つことを保証できます。
function Parent(name) {
this.name = 名前;
this.colors = ['red', ' yellow'];
}
Parent.prototype.sayName = function() {
alert(this.name);
}
function Child(name, age) {
Parent.call(this, name); //2 回目の Parent() の呼び出し
this.age = age; 🎜>}
Child.prototype = new Parent(); //初めて Parent() が呼び出されるとき、親クラスのプロパティは
Child.prototype.sayAge = function() {
alert(this.age );
}
var c1 = new Child('zhangsan', 20);
var c2 = new Child('lisi', 21); 🎜>c1.colors.push( 'blue');
alert(c1.colors); //赤、黄、青
c1.sayName(); //zhangsan
c1.sayAge(); ; //20
alert(c2.colors); //赤、黄
c2.sayName(); //21
組み合わせ継承 問題は、スーパータイプ コンストラクターが毎回 2 回呼び出されることです。1 回はサブタイプ プロトタイプの作成時、もう 1 回はサブタイプ コンストラクター内で呼び出されます。これにより、サブタイプ コンストラクターには親クラスの属性が含まれ、サブクラスのプロトタイプ オブジェクトにも親クラスの属性が含まれます。
3. 寄生組み合わせ継承 - 最も完璧な継承方法
いわゆる寄生組み合わせ継承とは、コンストラクターを借用してプロパティを継承し、プロトタイプ チェーンのハイブリッド形式でメソッドを継承することを意味します。 その背後にある基本的な考え方は次のとおりです。スーパータイプのコンストラクターを呼び出してサブクラスのプロトタイプを指定する代わりに、必要なのはスーパータイプのプロトタイプのコピーだけです
var F = function(){} //空のコンストラクターを定義します F.prototype =parent.prototype; //親クラスのプロトタイプとして設定します
child.prototype = new F(); //サブクラスのプロトタイプを F のインスタンスとして設定し、プロトタイプ チェーンを形成します
child .prototype.constructor = child; // サブクラス コンストラクター ポインターを再割り当てします
}
function Parent(name) {
this.name = name; ' 赤', '黄'];
}
Parent.prototype.sayName = function() {
alert(this.name);
function Child(name) , age) {
Parent.call(this, name);
this.age = age;
extend(Child, Parent); // 継承を実装します。 .prototype.sayAge = function() {
alert(this.age);
var c1 = new Child('zhangsan', 20); ( 'lisi', 21);
c1.colors.push('blue'); //red, yellow,blue
c1.sayName(); ; //張山
c1.sayAge(); //20
alert(c2.colors); //lisi
c2.colors; ) ; //21