1. 藉助構造函數實現繼承
function Parent1() {
this.name = 'Parent1';
}
Parent1.prototype.say = function() {
console.log('你好');
}
function Child1() {
Parent1.call(this); // !!!關鍵點 apply也可以
this.type = 'child1';
}
let s1 = new Child1();
console.log(s1);
s1.say(); // 此處會報錯
關鍵是 Parent1.call() 這一句,是通過call(apply)改變函數運行上下文,將Parent1的this掛載到Child1的實例上
缺點1:Parent1原型鏈上邊的屬性方法等不會被繼承。
2.藉助原型鏈繼承
function Parent2() {
this.name = 'parent2';
this.arr = [1,2,3];
}
function Child2() {
this.name = 'child2'
}
Child2.prototype = new Parent2(); // 此處爲關鍵
let s2 = new Child2();
let s3 = new Child2();
console.log(s2.arr, s3.arr) // [1,2,3] [1,2,3]
如上,關鍵在於將Child2的原型指向Parent2的實例
缺點1:這樣構造的Child2的實例,都是同一個原型,改變其中一個,其他的實例也會改變
如,接上邊,再增加一句
s2.arr.push(4);
console.log(s2.arr, s3.arr); //[1,2,3,4] [1,2,3,4]
可見,修改s2的arr屬性,s3實例也跟着變化
3.組合繼承 (解決上邊缺點1、2)
// 組合繼承
function Parent3() {
this.name = 'parent3';
this.arr = [1,2,3];
}
function Child3() {
Parent3.call(this);
this.name = 'child3'
}
Child3.prototype = new Parent3();
let s4 = new Child3();
let s5 = new Child3();
s4.arr.push(4)
console.log(s4.arr, s5.arr) // [1,2,3,4] [1,2,3]
缺點3: Child3每次實例化,都要執行Parent3 構造函數,
4.組合繼承的優化1
function Parent4() {
this.name = 'parent4';
this.arr = [1,2,3];
}
function Child4() {
Parent4.call(this);
this.name = 'child4'
}
Child4.prototype = Parent4.prototype; // !!!此處爲關鍵
let s6 = new Child4();
let s7 = new Child4();
s6.arr.push(4)
console.log(s6.arr, s7.arr)
缺點4: 無法區分實例是由Child4還是Parent4直接實例化而來
console.log(s6 instanceof Child4, s6 instanceof Parent4); // 可以發現此時均爲 true
console.log(s6.constructor, s7.constructor); // 均爲Parent4
5.組合繼承2
function Parent5() {
this.name = 'parent5';
this.arr = [1,2,3];
}
function Child5() {
Parent5.call(this);
this.name = 'child5'
}
Child5.prototype = Object.create(Parent5.prototype); // !! 此處爲關鍵
let s8 = new Child5();
let s9 = new Parent5();
console.log(s8 instanceof Child5, s9 instanceof Child5); // true, false
console.log(s8.constructor, s9.constructor); // 均爲Parent5
關鍵在於,通過 Object.create 構造一箇中間對象,用以區分
缺點:兩者 constructor 還是全部指向 Parent5
可通過如下手動設置,解決
Child5.prototype.constructor = Child5;