原型鏈實現(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。