記事のディレクトリ
継承方法には、コンストラクタ継承、プロトタイプチェーン継承、結合継承、プロトタイプ継承、寄生継承、寄生結合継承の6つがあります。
1つは、コンストラクターの継承
関数を使用して継承を実装する
//父类构造函数
function Father(){
this.name = "Father";
this.say = function(){
console.log(this.name);
}
}
//子类构造函数
function Son(){
Father.call(this); // 重点
}
重要:呼び出しを使用して、親クラスのコンストラクターをサブクラス関数に導入します(親クラスはサブクラス関数にコピーされます)
テスト:
let son1 = new Son();
son1.say(); // Father
son1は、親クラスのname属性とsayメソッドを正常に継承しました。
ただし、これは従来の意味での継承ではありません。親クラスを呼び出す各Sonサブクラスによって生成されたオブジェクトは互いに独立しているためです。つまり、親クラスがすべてのサブクラスインスタンスで共有される共通の属性を持ちたい場合は、達成できません。
利点:
- 複数のコンストラクターを継承できます(複数の呼び出しが可能です)
- すべての基本属性は独立しており、他のインスタンスの影響を受けません
短所:
- 親クラスコンストラクター(.prototype)のプロパティとメソッドを継承できません
- 新しいインスタンスごとに親コンストラクターがコピーされます。親クラスが非常に大きい場合は、メモリを消費します
- パブリックメソッドの再利用(関数の再利用)は実装されておらず、共有する代わりに毎回新しい関数が作成されます
2.プロトタイプチェーンの継承
プロトタイプのプロパティ継承による最も原始的な方法
//父级 构造函数
function Father() {
this.arr = [1,2,3];
}
//父级 原型属性
Father.prototype.name = "tingting"
//子级 构造函数
function Son() {
}
//子级 原型属性: 继承父级
Son.prototype = new Father() // 重点
//创建子级的实例对象
let son = new Son();
console.log(son.name); // tingting
重要:サブクラスのプロトタイプは、親クラスのインスタンスと同じです Son.prototype = new Father()
息子インスタンスが名前属性を見つける方法を説明します。
オブジェクトの特定の属性が見つからない場合、オブジェクトはプロトタイプに沿って検索し、プロトタイプチェーンの最後まで検索を停止します。
- 見つからない場合は、息子オブジェクト自体を最初に検索します
- 見つからない場合は、Son.prototypeで(Father())を見つけます
- 上位レベル
Son.prototype.__proto__
(Father.prototype) - 必要なプロパティまたはメソッドが見つかるまで、またはプロトタイプチェーンの最上位に到達するまでObject.prototype
ただし、子インスタンスのすべての属性とメソッドは親クラスの同じインスタンス上にあるため、子インスタンスがそのメソッドを変更すると、他のすべての子インスタンスが影響を受けます。
次のコードを見てください。
function Father() {
this.arr = [1,2,3];
}
function Son() {
}
Son.prototype = new Father()
let son1 = new Son();
let son2 = new Son();
son1.arr.push(4);
console.log(son1.arr); // 1,2,3,4
console.log(son2.arr);// 1,2,3,4
子インスタンスson1がarrを変更した後、son2インスタンスのarrも変更されます
利点:
- シンプル
短所:
- 親クラスコンストラクターにパラメーターを渡すことができません
- すべてのインスタンスは親インスタンスのプロパティを共有します(インスタンスが変更されると、すべてのプロパティが変更されます)
3、構成継承(プロトタイプチェーン+コンストラクター)
プロトタイプチェーン継承とコンストラクター継承の借用を組み合わせて、一般的に使用される2つの利点を統合します
function Father(color) {
this.color = color;
}
Father.prototype.print = function() {
console.log(this.color);
}
function Son(color) {
Father.call(this, color); // 借用构造函数继承
}
Son.prototype = new Father(); // 原型链继承
let son1 = new Son('red');
son1.print(); // red
let son2 = new Son('blue');
son2.print(); // blue
Sonサブクラスでは、Father.callを使用して親クラスコンストラクターを呼び出し、Son.prototypeを親クラスインスタンスに割り当てます
。Father.callを使用して親クラスコンストラクターを呼び出すと、new Son()
コピーをコピーして作成された後続のすべてのインスタンス親クラスのコンストラクタで定義されたプロパティとメソッドの、
そしてサブクラスのプロトタイププロトタイプに親クラスのインスタンスを割り当てて、すべてのサブクラスのインスタンスは、親クラスのプロトタイプのプロパティとメソッドを共有することができます;
場合はので、親クラスを定義する書き込みを、プライベート入れますコンストラクターにプロパティとメソッドを配置し、プロトタイプに共有プロパティとメソッドを配置します
利点:
- パラメータを渡すことができます
- 共通の機能を再利用できる
デメリット: - 親クラスコンストラクターを2回呼び出し、メモリを占有しました
4、プロトタイプの継承
プロトタイプ継承の本質は、実際には浅いコピーであり、オブジェクトをテンプレートとして使用して新しいオブジェクトをコピーします
// 封装一个函数容器,用来承载继承的原型
function object(obj){
function F(){
}
F.prototype = obj;
return new F();
}
let father = {
name: "father",
arr: [1,2,3]
}
let son1 = object(father);
オブジェクト関数で、コンストラクターを定義し、objをテンプレートとして使用し、コンストラクターのプロトタイプオブジェクトがobjを指すようにしてから、コンストラクターのインスタンスを返すと、オブジェクトobjのすべてのプロパティとメソッドにアクセスできます。
Object.creat()
プロトタイプの継承を直接実装するために、新しい関数Object.create()がes5に追加されました。
上記のコードは次のように書き直すことができます。
let father = {
name: "father",
arr: [1,2,3]
}
let son1 = Object.create(obj);
本質はまだプロトタイプチェーン継承であり、これも親クラスのプロパティを共有します
5、寄生継承
寄生継承とは、プロトタイプ継承を再度カプセル化し、オブジェクトの新しいメソッドを拡張して、新しいオブジェクトを返すことです。これ
は、プロトタイプ継承に基づいていくつかの関数またはプロパティを追加することとして理解できます。
function object(obj){
function F(){
}
F.prototype = obj;
return new F();
}
// 上面是原型式继承
function create(obj){
let clone = object(obj) // 或 Object.create(obj)
clone.say = function(){
console.log('123');
}
return clone;
}
// 用create函数封装了一遍,又增添了say方法
let father = {
name: "father",
arr: [1,2,3]
}
let son = create(father);
son.say(); // 123
クローンはオブジェクトに新しいメソッドを追加し、最終的にクローンに戻り、オブジェクトによって返されたオブジェクトを継承します
利点:
- カスタムタイプを作成する必要はありません
短所:
- プロトタイプは使用されておらず、再利用できません
6.寄生複合継承(一般的に使用される)
最後の継承方法が最も完璧な解決策です。これ
はes6クラス文法の実現原理です。主な目的は、結合された継承で毎回新しい父が必要になるという欠点を解決することです。これにより、親クラスコンストラクターが実行されます。 。
function Father(color) {
this.color = color;
}
Father.prototype.print = function() {
console.log(this.color);
}
function Son(color) {
Father.call(this, color);
}
Son.prototype = Object.create(Father.prototype); // 划重点
let son1 = new Son('red');
son1.print(); // red
let son2 = new Son('blue');
son2.print(); // blue
これは継承の組み合わせとは異なり、唯一のものは、元のSon.prototype = new Father();
改訂されたものですSon.prototype = Object.create(Father.prototype);
Object.create
プロトタイプで説明されている方法は、入力オブジェクトをプロトタイプとして新しいオブジェクトを作成することです。新しいオブジェクトが作成された後、に割り当てられるためSon.prototype
、Sonのプロトタイプは、最終的には親クラスのプロトタイプオブジェクトを指します。これnew Father
は同じです。の効果、およびメモリを占有する冗長インスタンスを作成しませんが、多重継承を実現することもできます。