JS面向對象 繼承的幾種方式

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;

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章