Javascript 繼承

    說到繼承,先來個開胃菜:求方法實現 f(6).num(1),結果等於6。
    想到方法了嗎?不如先來看一段代碼:

var $ = function(selector){
    return new $.prototype.init(selector)
};
$.prototype = {
    constructor:$,
    init:function(selector){
        this.length = selector
    },
    product(val){
        return val * this.length
    },
    length:0
};
$.prototype.init.prototype = $.prototype; //關鍵
console.log($(6).product(1));  


如果研究過jQuery源碼,應該瞭解,這就是jQuery面向對象的基本思路,關鍵點在繼承,子類繼承父類的原型屬性和方法。jQuery的巧妙在於:子類同時也是父類的一個原型方法


 1、利用 call、apply 繼承

function Food(i){
    this.name = i;
}
Food.prototype.use = "eat";
function Fish(x,y,z){    
    Food.apply(this,[z]);    //Food.call(this,z)     x可省略
    this.color = x;
    this.weight = y    
}
var fish = new Fish("golden","1kg","Salmon");
console.log(fish.name,fish.use);//fish.use:undefined 說明不能繼承父類原型的屬性和方法

缺點:不能繼承父類**原型**的屬性和方法

 

 2、原型鏈繼承

function Food(i){
    this.name = i;
}
Food.prototype.use = "eat";
var food = new Food("Cod");
function Fish(x,y){     
    this.color = x;
    this.weight = y 
}
Fish.prototype = new Food("Salmon");  
console.log(Fish.prototype.constructor === Food);//true 此時,構造函數已經指向了Food
Fish.prototype.constructor = Fish;      //因爲“Fish.prototype = new Food("Salmon");”將構造函數指向了Food,需要再次指回Fish
var fish = new Fish("golden","1kg");
console.log(fish.name,fish.use);


缺點
· 繼承時,要再次生成父類實例,耗費內存;
· 子類要添加屬性和方法,只能在“Fish.prototype = new Food("Salmon");”後面。

 

 3、直接繼承prototype

 

function Food(i){
    this.name = i
}
function Fish(x,y){        
    this.color = x;
    this.weight = y    
}
Fish.prototype = Food.prototype;    //相當於完全刪除了prototype 對象原先的值
console.log(Fish.prototype.constructor === Food);    //true,同樣,構造函數已經指向了Food
Fish.prototype.constructor = Fish;    
console.log(Food.prototype.constructor === Fish);    //true true  問題所在:父類和子類的構造函數,都指向了同一個對象:Fish

var fish = new Fish("golden","1kg");
console.log(fish.name,fish.color);//fish.name:undefined 說明不能繼承父類構造函數內的屬性和方法


缺點:
· 只能繼承父類**原型**的屬性和方法,不能繼承父類構造函數內的屬性和方法;
· 父類和子類的構造函數都指向了同一個對象。


 4、 Object.create(父類原型)
Object.create()方法創建一個新對象,使用現有的對象來提供新創建的對象的__proto__。
基於方法3的優化,解決了父類和子類的構造函數指向同一個對象的問題。

function Food(i){
    this.name = i
}
Food.prototype.use = "eat";
function Fish(x,y){    
    this.color = x;
    this.weight = y    
}
Fish.prototype = Object.create(Food.prototype);
Fish.prototype.constructor = Fish;    
console.log(Food.prototype.constructor === Food,Fish.prototype.constructor === Fish);    //true true
var fish = new Fish("golden","1kg","Salmon");
console.log(fish.name,fish.use);                    //undefined "eat"


缺點:只能繼承父類原型的屬性和方法,不能繼承父類構造函數內的屬性和方法;

 

5、call/apply + Object.create(父類原型)

 

function Food(i){
    this.name = i
}
Food.prototype.use = "eat";

function Fish(x,y,z){    
    Food.call(this,z);    
    this.color = x;
    this.weight = y    
}
Fish.prototype = Object.create(Food.prototype);
Fish.prototype.constructor = Fish;
var fish = new Fish("golden","1kg","Salmon");
console.log(fish.name,fish.use);


這樣,前面的問題,都有效得到解決,算是比較完美的一個方案。

 

 6、ES6 class


ES6中加入了靜態方法和屬性,也能通過 extends 繼承

class Food{
    static staticFn(){
        return "static-fn"
    };
    static staticVal = "static-val";
    constructor(i){
        this.name = i
    };
    info(){
        return "demo-"+this.name
    }

}
class Fish extends Food{    
    constructor(x,y,z){
        super(z);    
        this.color = x;
        this.weight = y    
    }
}
const fish = new Fish("golden","1kg","Salmon");
console.log(fish.name,fish.info());
console.log(Fish.staticFn(),Fish.staticVal);

最後,提前祝各位大小朋友:六一兒童節快樂!

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