前端面試必考的八種JS原型繼承方法

什麼是js繼承?

定義bash

        若是一個類可以重用另外一個類的屬性和或方法,就稱之爲繼承。閉包

        面向對象的語言多數都支持繼承。
app

特色: 函數

       子類可使用父類的全部功能,而且對這些功能進行拓展。學習

       繼承最重要的優勢就是代碼複用,從而構建大型軟件系統。ui

原型鏈繼承 (傳統形式)

缺點: this

        過多的繼承了沒用的屬性spa

Grand.prototype.lastName = 'chen'
function Grand() {}
var grand = new Grand();
Father.prototype = grand;
function Father() {    
    this.name = 'hehe';
}
var father = new Father();
Son.prototype = father;
function Son() {}
var son = new Son();

複製代碼

借用構造函數(類式繼承)

優勢:prototype

        能夠傳參

缺點: code

        不能繼承借用構造函數的原型

        每次構造函數都要多走一個函數 

function Person(name, age, sex) { 
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name, age, sex, grade) {
    Person.call(this, name, age, sex);
    this.grade = grade;
}
var student = new Student('hehe', 40, 'male', 18);複製代碼

組合式繼承(通俗來說就是用原型鏈實現對原型屬性和方法的繼承 用借用構造函數來實現對實例屬性的繼承)

優勢:

        避免了原型鏈和構造函數的缺陷 融合他們的優勢 成爲JavaScript中最經常使用的繼承模式

缺點:

        實例和原型上存在兩份相同的屬性    

Father.prototype.getfaName = function() {  
    console.log(this.faName);
}
function Father(name) {    
    this.faName = 'father';
}
Child.prototype = new Father();
Child.prototype.constructor = Child;
function Child(args) {    
    this.chName = 'child';
    Father.apply(this, args);
}
var child = new Child(); 複製代碼

原型式繼承    

缺點:

        不能隨便改動本身的原型

function create(o){
    function F(){};
    F.prototype = o; 
    return new F();        
}        
var Person = {
    name:'me',            
    hobbies:['riding', 'swimming']  
}
var anotherPerson = create(Person);
var anotherPerson2 = create(Person);
anotherPerson.name = 'her';
anotherPerson.hobbies.push('dancing');        
console.log(anotherPerson2.name, anotherPerson2.hobbies); // her ["riding", "swimming", "dancing"]複製代碼

寄生式繼承

缺點:

        跟借用構造函數模式同樣,每次建立對象都會建立一遍方法。

function createObj(o){   
    let clone = Object.create(o);            
    clone.sayName = function(){ 
        console.log('hi');            
    }
    return clone        
}        
let person = {            
    name:"JoseyDong",            
    hobbies:["sing","dance","rap"]        
}        
let anotherPerson = createObj(person);        
anotherPerson.sayName(); // => hi複製代碼

聖盃模式(寄生組合繼承)  

// 第一種寫法
function inherit(Target, Origin) {   
    // 使用F空函數當子類和父類的媒介 是爲了防止修改子類的原型對象影響到父類的原型對象 
    function F() {}
    F.prototype = Origin.prototype;
    Target.prototype = new F(); 
    Target.prototype.constructor = Target; // 防止new的時候 返回實例的構造函數指向混亂  
    Target.prototype.uber = Origin.prototype; // 尋找繼承的原型是誰
}

// 第二種寫法 採用當即執行函數和閉包的形式
var inherit = (function() {
    function F() {}    
    return function(Target, Origin) {   
        F.prototype = Origin.prototype;
        Target.prototype = new F(); 
        Target.prototype.contructor = Target; 
        Target.prototype.uber = Origin.prototype;
    }
})()複製代碼

對象冒充

缺點:

         但對象冒充有個問題,當父類的屬性相同時,後面定義的會覆蓋前面定義的屬性,所以,對象冒充的方式支持父類的屬性不一樣時的狀況下比較合理。

         每次構造函數都要多走一個函數

function Father(color) {        
    this.color = color;        
    this.showColor = function () {            
        alert(this.color);        
    }    
}    
function Father1(color) {        
    this.color1 = color;        
    this.showColor1 = function () {            
        alert(this.color1);        
    }    
}    
function Child(color, color1) {        
    this.Method = Father;        
    this.Method(color);        
    delete this.Method;        
    
    this.Method = Father1;        
    this.Method(color1);        
    delete this.Method;    
}    
var child = new Child("wu", "zhao");    
child.showColor();複製代碼

ES6的extends繼承寫法

class Plane {   
    // 靜態方法 不被子集繼承 
    static alive() {        
        return true;    
    }    
    constructor(name) {        
        this.name = name || '普通飛機';        
        this.blood = 100;    
    }    
    fly() {        
        console.log('fly');    
    }
};
class AttackPlane extends Plane{    
    constructor(name) {        
        super(name);        
        this.logo = 'duyi';    
x    }    
    dan() {        
        console.log('bububu');    
    }
}
var oAp = new AttackPlane('攻擊機');
console.log(oAp);複製代碼

注意: 

        子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類沒有本身的this對象,而是繼承父類的this對象,而後對其進行加工,若是不調用super方法,子類就得不到this對象。所以,只有調用super以後,纔可使用this關鍵字。

總結ES5與ES6繼承的區別?

ES5的繼承機制實質是先創造子類的實例對象this,而後再將父類的方法添加到this上面(Parent.call(this))。

ES6的繼承機制實質是先創造父類的實例對象this (因此必須先調用 super() 方法),而後再用子類的構造函數修改this。

你的點贊是我持續輸出的動力 但願能幫助到你們 互相學習 有任何問題下面留言 必定回覆 

相關文章
相關標籤/搜索