JavaScript經常使用的繼承方式

JavaScript經常使用繼承方式主要分爲(7種):原型鏈繼承、構造函數繼承、組合繼承、原型式繼承、寄生式繼承、寄生組合繼承以及繼承多個對象。函數

1:原型鏈繼承(核心:將父類的實例做爲子類的原型)

基本概念:重寫原型對象,賦予一個新的對象的實例。基本思想就是讓一個原型對象指向另外一個父類的實例。this

function Super() {
        //基本數據類型
        this.text = 'Hello';
    }
    Super.prototype.getSuperText = function() {
        return this.text;
    }
    function Sub() {
    	this.subText = 'Word';
    }
    
    Sub.prototype = new Super();
    
    const instance = new Sub();
    console.log(instance);

特色:很是純粹的繼承關係,實例是子類的實例,也是父類的實例。父類新增原型方法或屬性,子類都能訪問到。prototype

優勢:簡單易於操做code

缺點:對引用類型數據操做會互相(多個實例之間)影響對象

function Super() {
        //複雜對象,也就是引用類型
        this.value = [1, 2, 3, 4];
    }
    Super.prototype.getSuperValue = function() {
        return this.value;
    }
    function Sub() {
        this.subText = 'Word';
    }
    
    Sub.prototype = new Super();
    
    const instance1 = new Sub();
    const instance2 = new Sub();
    
    instance1.value.push(5);
    console.log(instance2.value);
    
    // (5) [1, 2, 3, 4, 5]

2:構造函數繼承

//定義構造函數
    function Super(){
        this.value = [1, 2, 3, 4];
    }
    //新增屬性getSuperValue
    Super.prototype.getSuperValue = function() {
        return this.value;
    }
    //sub每次執行都要從新調用
    function Sub(){
        Super.call(this);
    }
    
    const instance1 = new Sub();
    instance1.value.push(5);
    console.log(instance1.value);
    // (5) [1, 2, 3, 4, 5]
    
    const instance2 = new Sub();
    console.log(instance2.value);
    // (4) [1, 2, 3, 4]

構造函數的特色:(對引用數據類型沒有影響)上面的代碼輸出instance1是1,2,3,4,5,instance2是1,2,3,4。這是由於sub每次在執行時都是從新調用了一個super.call(),並且構造函數在構建對象的過程當中,每次都是建立了一個新的object,所以每次調用sub都會執行一遍super,每次執行時都會有申請一個新的內存空間,因此獲得的兩個value值是不同互不影響的。繼承

缺點:在整個構造函數的基礎過程當中,上面的代碼並無使用proto和prototype的屬性,沒有使用的話那麼原型鏈就沒有接上。因此說,構造函數基礎只能繼承父類的實例屬性和方法,不能繼承原型鏈上的屬性和方法ip

3:組合繼承

經過調用父類構造,繼承父類的屬性並保留傳參的優勢,而後經過將父類實例做爲子類原型,實現函數複用。內存

保留了構造函數繼承與原型鏈繼承的優勢。可是執行了兩次Person,屬性重複了。原型鏈

function Person(name) {
        this.name = name;
        this.value = ["head", "body", "legs"];
    }
    Person.prototype.getName = function() {
        return this.name;
    };
    
    // 構造函數繼承
    function Teacher(name, school){
        // 執行又一次Person
        Person.call(this, name);
        this.school = school;
    }
    
    // 原型鏈繼承
    // 執行一次Person
    Teacher.prototype = new Person(); 
    const Eric = new Teacher("Eric",27);
    Eric.getName();
    // 輸出:Eric
    
    
    
    // prototype構造器指回本身 
    Teacher.prototype.constructor = Teacher;
    
    Teacher.prototype.getSchool = function() {
        return this.school;
    };

特色:既能夠繼承實例屬性和方法,也能夠繼承原型屬性和方法。既是子類的實例也是父類的實例,不存在引用屬性共享的問題。能夠傳參,函數可複用。get

缺點:調用兩次父類構造函數,生成了兩份實例。

4:原型式繼承

藉助原型能夠基於已有的對象建立新的對象,同時還沒必要所以建立自定義類型。

原理:(本質)利用一個空對象做爲一箇中介。

const lakers = {
        name: "lakers",
        value: ["Micheal", "Wade", "Kobe"]
    };
    
    const lakers1 = Object.create(lakers);
    const lakers2 = Object.create(lakers);
    
    lakers1.value.push('Fish');
    console.log(lakers);

模擬Object.create()

object.create()原理:用一個函數包裝一個對象,而後返回這個函數的調用,這個函數就變成了一個能夠隨意添增屬性的實例或對象。

Object.prototype.create = function(obj) {
        function Fun() {}
        Fun.prototype = obj;
        return new Fun();
    }

缺點有兩點:第一點是沒法傳遞參數,第二點是引用類型存在變量的污染。****

5:寄生式繼承

寄生式繼承的思路與寄生構造函數和工廠模式相似,即建立一個僅用於封裝繼承過程的函數。

目的:在原型式繼承的基礎上,寄生增長了一些新的方法和屬性。

它的特色同原型式繼承同樣,也是沒法傳遞參數,並且引用的數據類型也容易存在樣式污染。

Object.createNew()

Object.prototype.createNew = function(obj){
        var newObj = Object.create(obj);
        //獲取長度等於一個function
        newObj.getLength = function(){ ... };
        return newObj;
    }

6:寄生組合繼承

目的:爲了解決數據重複拷貝兩遍的問題。

Super只執行一次。

//定義Super構造函數
    function Super(name) {
      this.name = name;
      this.value = ["Hello", "Word"];
    }
    //在super的原型鏈添加一個getName
    Super.prototype.getName = function() {
      return this.name;
    };
    //定義Sub
    function Sub(name, age) {
      //調用構造函數繼承
      Super.call(this, name);
      this.age = age;
    }
    
    let prototype = Object.create(Super.prototype);
    prototype.constructor = Sub;
    Sub.prototype = prototype;
    
    Sub.prototype.getAge = function(){
      return this.age;
    }
    
    const instance1 = new Sub("Eric", 23);
    const instance2 = new Sub("Vico", 23);
    instance1.value.push("!");
    instance2.value.push("!!");

7:繼承多個對象

藉助原型式繼承Object.create拿到SuperClass,也就是父類,拿到父類的prototype以後把它賦給ClassOne,

再而後咱們將ClassTwo的prototype使用一個Object.assign,一個對象的拷貝,把它拷貝到ClassOne裏面來,

而後最後ClassOne.prototype.constructor等於ClassOne

也就是使用一個Class.assign把全部咱們想要繼承的父類的prototype所有組合到一塊兒完成一個拷貝,以後再賦給對象。

function 
    
    ClassOne.prototype = Object.create(SuperClass.prototype);
    
    Object.assign(ClassOne.prototype, ClassTwo.prototype);
    
    ClassOne.prototype.constructor = ClassOne;
相關文章
相關標籤/搜索