說到繼承呢?確定有不少作java的朋友都以爲是一個比較簡單的東西了。畢竟面向對象的三大特徵就是:封裝、繼承和多態嘛。可是真正對於一個javascript開發人員來講,不少時候其實你使用了繼承,但其實你不知道這叫繼承。今天我就借這篇文章來談一談繼承在前端的幾種實現方式。javascript
function Animal(name = 'animal'){
this.name = name
}
Animal.prototype.eat = function(food){
console.log('dasdsa')
return `${this.name} eat ${food}`;
}
function Dog(){
}
Dog.prototype = new Animal();
var instance = new Dog();
instance.name = 'dog';
console.log(instance.eat('bone'));
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true
複製代碼
可是原型繼承有有有些缺點,來看下面一段代碼:前端
function Animal(name = 'animal'){
this.name = name
this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
return `${this.name} eat ${food}`;
}
function Dog(){
}
Dog.prototype = new Animal();
var instance = new Dog();
instance.name = 'keji';
instance.skinColors.push('red');
console.log(instance.eat('bone'));
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true
var instance1 = new Dog()
console.log(instance1.skinColors) // [ 'black', 'white', 'red' ]
複製代碼
從上面的代碼,咱們能夠清楚的發現:全部的實例都會公用一個原型鏈,若是一個實例中修改原型 那麼全部實例的值都會被修改。java
針對前面原型鏈繼承可能會存在公用一個原型鏈的問題,那麼咱們能夠給你們介紹一種方式:構造函數的繼承。構造函數的繼承至關於將父類複製給子類。es6
function Animal(name = 'animal'){
this.name = name
this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
return `${this.name} eat ${food}`;
}
function Dog(){
Animal.call(this);
}
var instance = new Dog();
instance.name = 'keji';
instance.skinColors.push('red');
console.log(instance.eat('bone')); // TypeError: instance.eat is not a function
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true
var instance1 = new Dog();
console.log(instance1.skinColors); // [ 'black', 'white' ]
複製代碼
可是這種方法也有本身缺點:bash
原型鏈繼承能繼承父類原型鏈上的屬性,可是可能會存在篡改的問題;而構造函數繼承不會存在篡改的問題,可是不能繼承原型上面的屬性。那麼咱們是否是能夠將二者進行結合呢?函數
function Animal(name = 'animal'){
this.name = name
this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
return `${this.name} eat ${food}`;
}
function Dog(){
Animal.call(this);
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
var instance = new Dog();
instance.name = 'keji';
instance.skinColors.push('red');
console.log(instance.eat('bone'));
console.log(instance.skinColors) // [ 'black', 'white', 'red' ]
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true
var instance1 = new Dog()
console.log(instance1.skinColors) // [ 'black', 'white' ]
複製代碼
這種方法呢?調用了兩次父類的構造函數,有些許損耗性能,而且子類的構造函數的屬性會和原型上面的屬性相重合。(優先原用構造函數的屬性)性能
function object(obj){
function F(){}
F.prototype = obj;
return new F();
}
let Programmer = {
features:["tutou","jiaban","single"]
}
// 方式一:最原始的作法
var programmer1 = object(Programmer);
programmer1.features.push('meiqian');
console.log(programmer1.features); // [ 'tutou', 'jiaban', 'single', 'meiqian' ]
var programmer2 = object(Programmer);
console.log(programmer2.features); // [ 'tutou', 'jiaban', 'single', 'meiqian' ]
// 方式二 es中的Object.create
var programmer3 = Object.create(Programmer);
console.log(programmer3.features); // [ 'tutou', 'jiaban', 'single', 'meiqian' ]
複製代碼
從上面的代碼很明顯的能夠發現:和構造函數繼承同樣也存在被篡改的可能,而且也不能傳遞參數。ui
在原型式繼承的基礎上面加強了對象,並返回構造函數。this
function pFactory(obj){
let clone = Object.create(obj);
clone.motto = function(){
console.log('hardworking and not lazy!!')
}
return clone;
}
var programmer1 = new pFactory(Programmer);
console.log(programmer1.motto()); // hardworking and not lazy!!
console.log(programmer1.features); // [ 'tutou', 'jiaban', 'single' ]
複製代碼
這種繼承的方法一樣和原型繼承同樣,存在被篡改的可能。es5
前面說了這麼多,每種繼承方式都有本身的優勢和缺點,那麼是否是能夠將這些繼承的方式作一個合併:以他之長補己之短呢?來看下面一段代碼:
function Animal(name = 'animal'){
this.name = name
this.skinColors = ['black','white']
}
Animal.prototype.eat = function(food){
return `${this.name} eat ${food}`;
}
function inheritPrototype(subType, superType){
var prototype = Object.create(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype;
}
function Dog(name,sound){
Animal.call(this,name);
this.sound = sound;
}
inheritPrototype(Dog,Animal);
Dog.prototype.getSound = function(){
console.log(`${this.name} ${this.sound}`);
}
var instance = new Dog('keji','wangwangwang!!!');
instance.skinColors.push('red');
console.log(instance.eat('bone'));
console.log(instance.skinColors) // [ 'black', 'white', 'red' ]
console.log(instance instanceof Dog); // true
console.log(instance instanceof Animal); // true
console.log(instance.getSound()) // keji wangwangwang!!!
var instance1 = new Dog('haha','wangwang!!!')
console.log(instance1.skinColors) // [ 'black', 'white' ]
console.log(instance1.getSound()) // haha wangwang!!!
複製代碼
這個例子的效率的體如今它只調用了一次父類的構造函數,這很大程度上面減小建立了沒必要要多餘的屬性。而且還能繼承原型鏈上面的方法。這個方法是如今庫的實現方法。
class Animal {
constructor(name){
this.name = name;
}
get getName(){
return this.animalName()
}
animalName(){
return this.name;
}
}
class Dog extends Animal{
constructor(name,sound){
super(name);
this.sound = sound;
}
get animalFeature(){
return `${this.getName} ${this.sound}`
}
}
let dog = new Dog('keji','wangwangwang!');
console.log(dog.animalFeature); // keji wangwangwang!
複製代碼
其實咱們曉得,class語法也是由es5語法來寫的,其繼承的方法和寄生組合式繼承的方法同樣。關於es6的類,我在代碼自檢的時候遇到的兩個重點,值得注意下的是:
好像什麼都沒寫就差很少快12點了,最近在瘋狂的複習。可是卻發現越學東西越多,感受有點學不完的意味在裏面 外加上最近好像有點高考考砸以後的失眠綜合症,搞的我整我的都不怎麼舒服。明明高考都過去差很少6年了,還一直困擾着我,賊恐怖,算了 算了 先不寫了 睡覺去了。