JS繼承的幾種方式

原型鏈實現(xiàn)繼承

? ? ? ?通過重寫子類的原型,并將它指向父類的手段實現(xiàn)。這種方式實現(xiàn)的繼承,創(chuàng)建出來的實例既是子類的實例,又是父類的實例。它有如下幾種缺陷:

? ? ? ?不能向父類構造函數(shù)傳參;

? ? ? ?父類上的引用類型屬性會被所有實例共享,其中一個實例改變時,會影響其他實例。

function Animal() {

? this.colors = ['red','blue'];

}

function Dog(name) {

? this.name = name;

}

Dog.prototype = new Animal();

var dog1 = new Dog('旺財');

var dog2 = new Dog('鋼镚');

dog2.colors.push('yellow');

console.log(dog1.colors); // ["red", "blue", "yellow"]

console.log(dog2.colors); // ["red", "blue", "yellow"]

console.log(dog1 instanceof Dog);? // true

console.log(dog1 instanceof Animal);// true


構造函數(shù)實現(xiàn)繼承

? ? ? ? 借用構造函數(shù)實現(xiàn)繼承,通過在子類中使用call()方法,實現(xiàn)借用父類構造函數(shù)并向父類構造函數(shù)傳參的目的。但這種方法,無法繼承父類原型對象上的屬性和方法。

function Animal(name) {

? this.name = name;

? this.colors = ['red','blue'];

}

Animal.prototype.eat = function() {

? console.log(this.name + ' is eating!');

}

function Dog(name) {

? Animal.call(this,name);

}

var dog1 = new Dog('旺財');

var dog2 = new Dog('鋼镚');

dog2.colors.push('yellow');

console.log(dog1.colors); // ["red", "blue"]

console.log(dog2.colors); // ["red", "blue", "yellow"]

console.log(dog1 instanceof Dog);? // true

console.log(dog2 instanceof Animal);// false

console.log(dog1.eat()); // 報錯


組合繼承??

? ? ? ? 組合繼承是組合了原型鏈繼承和借用構造函數(shù)繼承這兩種方法,它保留了兩種繼承方式的優(yōu)點,但它并不是百分百完美的:父類構造函數(shù)被調(diào)用多次。

function Animal(name) {

? this.name = name;

? this.colors = ['red','blue'];

}

Animal.prototype.eat = function() {

? console.log(this.name + ' is eatting');

}

function Dog(name) {

? Animal.call(this,name);

}

Dog.prototype = new Animal(); // 第一次調(diào)用

var dog1 = new Dog('dog1');? // 第二次調(diào)用

var dog2 = new Dog('dog2');? // 第三次調(diào)用

dog1.colors.push('yellow');

console.log(dog1.name);? // 輸出dog1

console.log(dog2.colors);// 輸出['red','blue']

console.log(dog2.eat()); // 輸出dog2 is eatting


寄生組合繼承

? ? ? ?寄生組合繼承是在組合繼承的基礎上,采用Object.create()方法來改造實現(xiàn)。

function Animal(name) {

? this.name = name;

? this.colors = ['red','blue'];

}

Animal.prototype.eat = function() {

? console.log(this.name + ' is eatting');

}

function Dog(name) {

? Animal.call(this,name);

}

Dog.prototype = Object.create(Animal.prototype);

Dog.prototype.constructor = Dog;

var dog1 = new Dog('dog1');

var dog2 = new Dog('dog2');

dog1.colors.push('yellow');

console.log(dog1.name);? // 輸出dog1

console.log(dog2.colors);// 輸出['red','blue']

console.log(dog2.eat()); // 輸出dog2 is eatting


Class實現(xiàn)繼承

1.ES6 class 內(nèi)部所有定義的方法都是不可枚舉的;

2.ES6 class 必須使用 new 調(diào)用;

3.ES6 class 不存在變量提升;

4.ES6 class 默認即是嚴格模式;

5.ES6 class 子類必須在父類的構造函數(shù)中調(diào)用super(),這樣才有this對象;ES5中類繼承的關系是相反的,先有子類的this,然后用父類的方法應用在this上。

class Animal {

? constructor(name) {

? ? this.name = name;

? ? this.colors = ['red','blue'];

? }

? eat() {

? ? console.log(this.name + ' is eatting');

? }

}

class Dog extends Animal {

? constructor(name) {

? ? super(name);

? }

}

var dog1 = new Dog('dog1');

var dog2 = new Dog('dog2');

dog1.colors.push('yellow');

console.log(dog1.name);? // 輸出dog1

console.log(dog2.colors);// 輸出['red','blue']

console.log(dog2.eat()); // 輸出dog2 is eatting

? ? ? ? ES5 的繼承,實質(zhì)是先創(chuàng)造子類的實例對象this,然后再將父類的方法添加到this上面(Parent.apply(this))。ES6 的繼承機制完全不同,實質(zhì)是先將父類實例對象的屬性和方法,加到this上面(所以必須先調(diào)用super方法),然后再用子類的構造函數(shù)修改this。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容