一、基本概念:
? ? JavaScript基于原型實現面向對象特性,在JS編程中,面向對象的繼承是重點,本文將從簡單開始介紹JS的繼承。
二、繼承方式:
1、借助構造函數實現繼承:
function Parent1(){
? ? this.name = 'parent1'
}
function Child1(){
? ? Parent1.call(this)
? ? this.type = 'child1'
}
? ? 父級構造函數在子級構造函數內使用call、apply方法,將自身的this指向子級實例,并執行,從而使得子級實例后擁有父級的屬性;
? ? 簡單,但是父級原型上的屬性無法繼承;
2、借助原型鏈繼承:
function Parent2(){
? ? this.name = 'parent2';
}
function Child2(){
? ? this.type = 'Child2';
}
Child2.prototype = new Parent2();
console.log(new Child2());
? ? Child2構造函數的屬性prototype指向一個原型對象,可以任意更改,將 Parent2 的實例作為Child2的原型對象,于是,當 new Child2 后生成的實例, 其 __proto__ 指向的原型對象就是 Child2的prototype指向的Parent2實例
? ? 這樣,子實例共享同一個繼承的實例的屬性,更改其中之一,會改變所有;沒有隔離;
3、組合繼承:
function Parent3(){
? ? this.name = 'parent3';
? ? this.play = [1,2,3,4];
}
function Child3(){
? ? Parent3.call(this);
? ? this.type = 'child3';
}
Child3.prototype = new Parent3();
var c31 = new Child3();
var c32 = new Child3();
c31.play.push(5);
console.log(c31, c32);
console.log(c31.constructor)
? ? 彌補了構造函數和原型鏈繼承的缺點, 但是,父級構造函數體執行了兩次,生成的實例無法判斷實例源(實例的constructor屬性指向父級的構造函數)。(詳細見組合優化1)
4、組合繼承的優化1:
function Parent4(){
? ? this.name = 'parent4';
? ? this.play = [1,2,3,4];
}
function Child4(){
? ? Parent4.call(this);
? ? this.type = 'child4';
}
Child4.prototype = Parent4.prototype;
var c41 = new Child4();
var c42 = new Child4();
c41.play.push(5);
console.log(c41, c42);
console.log(c41 instanceof Child4, c41 instanceof Parent4); // true true
console.log(c41.constructor); // 指向 Parent4
? ? 彌補了組合繼承 執行 2次的缺點, 但是,生成的實例,使用instanceof 判斷的時候,無法判斷該對象是由Parent5實例化或Child5實例化 , 使用實例的constructor屬性(實際為__proto__指向原型對象上的屬性),指向 Parent5.... 于是無法判斷該實例是由哪個構造函數實例化的;(組合繼承都有這個缺點)
5、組合繼承的優化2:
function Parent5(){
? ? this.name = 'parent5';
? ? this.play = [1,2,3,4];
}
function Child5(){
? ? Parent5.call(this);
? ? this.type = 'child5';
}
Child5.prototype = Object.create(Parent5.prototype); // 創建中間對象
Child5.prototype.constructor = Child5; // 中間對象的構造函數更改constructor
var c51 = new Child5();
var c52 = new Child5();
c51.play.push(5);
console.log(c51, c52);
console.log(c51 instanceof Child5, c51 instanceof Parent5);
console.log(c51.constructor);
? ? 彌補了前面繼承方式的缺點;完美~~~~~