JS面向對象編程(四):繼承

1、原型鏈繼承

  1. 原型鏈繼承:利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法
//父類
function SuperType(){ 
    this.SuperProperty = "SuperType property"; 
} 
//子類
function SubType(){ 
    this.subProperty = "SubType property";
} 

//子類SubType繼承了父類SuperType
SubType.prototype = new SuperType(); 

var instance = new SubType(); 
console.log(instance.SuperProperty) // 繼承父類的SuperProperty屬性
複製代碼

經過建立 SuperType 的實例,並將該實例賦給SubType.prototype 來實現繼承編程

  1. 全部引用類型默認都繼承了 Object,而這個繼承也是經過原型鏈實現的,SubType 繼承了 SuperType,而 SuperType 繼承了 Object。
console.log(instance instanceof Object); //true 
console.log(instance instanceof SuperType); //true 
console.log(instance instanceof SubType); //true 
複製代碼

缺點bash

  1. 在經過原型來實現繼承時,原型實際上會變成另外一個類型的實例。因而,原先的實例屬性也就瓜熟蒂落地變成了如今的原型屬性了。例如:
var instanceSup=new SuperType()
instanceSup.hasOwnProperty("SuperProperty")         //true

var instance=new SubType()
instance.hasOwnProperty("SuperProperty")    //false
複製代碼

 SuperProperty是SuperType()的實例屬性,是SubType()的原型屬性app

  1. 不能在不影響全部對象實例的狀況下,給父類型的構造函數傳遞參數

2、構造函數繼承

  1. 構造函數繼承:經過使用 call()或 apply()方法在子類型構造函數的內部調用父類型構造函數
function SuperType(){ 
    this.SuperProperty = "SuperType property"; 
} 
function SubType(){ 
 //繼承了 SuperType 
 SuperType.call(this); 
} 
var instance = new SubType(); 
console.log(instance.SuperProperty) // "SuperType property"
複製代碼
  1. SuperProperty是SuperType()的實例屬性,也是SubType()實例屬性
var instanceSup=new SuperType()
instanceSup.hasOwnProperty("SuperProperty")         //true

var instance=new SubType()
instance.hasOwnProperty("SuperProperty")    //false
複製代碼
  1. 傳遞參數相對於原型鏈而言,借用構造函數有一個很大的優點,便可以在子類型構造函數中向父類型構造函 數傳遞參數。例如:
function SuperType(name){ 
    this.name = name; 
} 
function SubType(){ 
    //繼承了 SuperType,同時還傳遞了參數
    SuperType.call(this, "lilei"); 
    //實例屬性
    this.age = 26; 
} 
var instance = new SubType(); 
console.log(instance.name); //"lilei"; 
console.log(instance.age); //26 
複製代碼

缺點:沒法繼承原型鏈上的屬性和方法函數

3、組合繼承

使用原型鏈實現對原型屬性和方法的繼承,而經過借用構造函數來實現對實例屬性和方法的繼承ui

function SuperType(name){ 
    this.name = name;
}
SuperType.prototype.country="China";

function SubType(name){
    //繼承屬性 
    SuperType.call(this,name);
}
SubType.prototype = new SuperType(); 
SubType.prototype.constructor = SubType;

var instance1 = new SuperType("lilei", 26);
var instance2 = new SubType("xiaoming", 22);
console.log(instance1.name)     // lilei
console.log(instance1.country)  // China
console.log(instance2.name)     // xiaoming
console.log(instance2.country)  // China
複製代碼

優勢:this

  1. 能夠繼承實例屬性/方法,也能夠繼承原型屬性/方法
  2. 可傳參
  3. 函數可複用

缺點:spa

  子類原型上有父類的實例屬性,子類實例屏蔽了子類原型上的屬性;prototype

4、原型式繼承

  1. 藉助原型能夠基於已有的對象建立新對象,同時還沒必要所以建立自定義類;例如:
function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}

function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();
var subType = object(superType);
console.log(subType.name) // "lilei"

複製代碼

把SuperType實例化的對象做爲參數傳給object函數,函數就會返回一個新對象。這個新對象將superType做爲原型。設計

  1. ECMAScript 5 經過新增 Object.create()方法規範化了原型式繼承。這個方法接收兩個參數:第一個做爲新對象原型的對象,另外一個做爲新對象定義額外屬性的對象(可選) 。例如:
function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();

var subType = Object.create(superType,{
    age: {
        value: "12"
    }
});

console.log(superType.name)     // "lilei"
console.log(subType.name)       // "lilei"
複製代碼

  額外屬性都會覆蓋原型對象上的同名屬性code

function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();

var subType = Object.create(superType,{
    name: {
        value: "haimeimei"
    }
});

console.log(superType.name)     // "lilei"
console.log(subType.name)       // "haimeimei"
複製代碼

優勢
 直接將父類對象生成新的對象傳遞給子類

缺點
 引用類型值的屬性始終都會共享相應的值,和使用原型模式同樣

5、寄生式繼承

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
function createObject(o){
    var clone=object(o); 
    clone.sayHello = function(){
        console.log("hello");
    };
    return clone;
}
function SuperType(){ 
    this.name = "lilei";
}
var superType = new SuperType();

var subType = createObject(superType);
subType.sayHello(); //"hello"
複製代碼

優勢:不須要建立自定義類型
缺點:沒法實現函數的複用

6、寄生組合式繼承

組合繼承的缺點是會調用兩次父類型構造函數,子類原型上有父類的實例屬性。所以咱們只要給子類原型賦父類原型的屬性。

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}
複製代碼

函數內部:

  1. 將父類原型地址賦值給變量prototype。
  2. 重寫原型會失去的默認的 constructor 屬性,因此添加一個constructor屬性。
  3. 把prototype賦值給子類型的原型。

舉個栗子:

function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}

function SuperType(name){ 
    this.name = name;
}
SuperType.prototype.country="China";

function SubType(name){
    SuperType.call(this,name);
}

inheritPrototype(SubType, SuperType);

SubType.prototype.country="America";

var superType = new SuperType("lilei");
var subType = new SubType("tom");

console.log(superType.name)     //"lilei"
console.log(superType.country)  //"China"
console.log(subType.name)       //"tom"
console.log(subType.country)    // "America"
複製代碼

優勢:解決了子類原型上有父類的實例屬性問題,是引用類型最理想的繼承範式
缺點:過程比較複雜

面向對象編程到此就完結啦,但願對你們有幫助!


文章參考:

《JavaScript 高級程序設計》中文譯本 第三版

相關文章
相關標籤/搜索