【前端】JavaScript繼承實現的四種方式


轉載請注明出處:http://www.cnblogs.com/shamoyuu/p/4770235.html

一、繼承的實現方法

1、原型鏈繼承

這個繼承最為簡單,它的實現原理是,每一個AO對象都有一個prototype,返回對象類型原型的引用,所以可以給它賦值一個對象,就可以實現簡單的原型鏈繼承。

function Animal(){
    this.eat = function(){
        alert("我會吃");
    }
}

function Bird(){
    this.fly = function(){
        alert("我會飛");
    }
}
//設置Bird類的原型為一個Animal對象
Bird.prototype = new Animal();

var pigeon = new Bird();
pigeon.fly();
pigeon.eat();

結果出現了,實現了鳥類繼承動物會吃的特性。打印一下console.info(pigeon)我們可以看到:

當前對象的__proto__屬性為一個Animal對象,而eat方法在這個Animal對象也就是它的父類里,如果一個屬性或方法在當前對象里無法找到的話,就會照着原型鏈一步一步找上去。

這里Bird的父類是Animal,Animal的父類是Object,或者說所有沒有直接指定prototype的對象,它的父類都是Object。因為toString()方法就是在Object里,所以所有對象都可以調用它。而Object的父類是null。

還有一個需要注意的問題是,原型鏈繼承中,所有的子類的父類對象都是同一個。只要任意一個子類改變了父類對象的屬性,那所有對象都會受到影響。這點可能是缺點,也可能是優點。

注:prototype和__proto__的區別可以看我另外一篇博客 http://www.cnblogs.com/shamoyuu/p/prototype.html

2、原型冒充繼承

原型冒充的原理是:把父類的構造函數拿過來執行一遍。下面看代碼:

function Animal(){
    this.eat = function(){
        alert("我會吃");
    }
}

function Bird(){
    Animal.apply(this, arguments);this.fly = function(){
        alert("我會飛");
    }
}

var pigeon = new Bird();
pigeon.fly();
pigeon.eat();

效果跟上面是一樣一樣的,但是這個時候eat方法已經不在原型鏈上,而是在pigeon對象上。

3、復制繼承

復制繼承的原理是:把父類所有的屬性和方法復制過來。下面看代碼。

function Animal(){
    this.eat = function(){
        alert("我會吃");
    }
}

function Bird(){
    this.fly = function(){
        alert("我會飛");
    }
    //這里寫一個繼承的方法,用來復制所有父類的屬性或方法
    this.extend = function(parent){
        for(var key in parent){
            this[key] = parent[key];
        }
    }
}

var pigeon = new Bird();
//執行繼承的方法
pigeon.extend(new Animal());

pigeon.fly();
pigeon.eat();

這個也和上面一樣一樣的。

 

4、ES6標准類的繼承

ES6中引入了class的概念,新的class能幫助我們寫出更好更直觀的面向對象的代碼。

下面這是ES6中類與類的繼承,實現的效果跟上面是一樣的。

class Animal {
    constructor(name){
        this.name = name;
        this.type = "動物";
    }
    
    says(say){
        console.info(this.type + "【" + this.name + "】" + "說 " + say);
    }
}

let dog = new Animal("狗狗");
dog.says("汪汪汪");


class Bird extends Animal {
    constructor(name){
        super(name);
        this.type = "小鳥";
    }
}

let pigeon = new Bird("鴿子");
pigeon.says("我是一只小鳥");

實現是非常簡單直觀的,而且不會再被人稱為這是“模擬繼承”。

 

二、各有什么缺點

1、原型鏈繼承利弊

1、只能單繼承。2、繼承后會影響所有的對象。3、速度略慢。

2、原型冒充繼承利弊

1、雖然可以多繼承,但是無法在運行的時候動態繼承,只能修改父類的構造函數。

3、復制繼承(非ES6推薦)

1、無。

因為上面兩個所擁有的缺點它都很好地避開了,它可以實現多繼承,繼承只影響當前對象,而且速度快,不必修改父類的構造函數等等等等,所以最推薦的還是這種繼承方式。

注:jQuery的繼承也是采取復制繼承實現的,不過jQuery加了很多的驗證判斷,但是原理是一樣的。

4、ES6標准類的繼承

如果能使用最新的ES6的特性,這種繼承是最好的,通俗易懂,是標准的面向對象的語言該有的繼承方式。

但是需要注意:

子類的contructor里,“this”必須放在super()調用之后

子類的contructor里必須調用super(),或者明確地返回一個對象

不能多繼承

-- Java在繼承的時候會自動生成一個父類對象,但是js里並不會

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM