JS 經常使用繼承方式(7種)

前言

關於繼承,在ES 6 以前,只支持實現繼承 ,且實現繼承主要是依靠原型鏈繼承,即便Class 的extends 也是基於原型繼承(語法糖),下面的內容中會詳細介紹,各位看官往下瞧javascript

原型鏈繼承

定義
  • 子類能夠經過原型鏈的查找,實現父類的屬性公用與子類的實例
  • 子類添加的新方法不能使用對象字面量的形式添加
缺點
  • 一些引用數據操做的時候會出問題,兩個實例會公用繼承實例的引用數據類
實現
function SuperType (){
  this.property = true;
  this.colors = ["red", "blue", "green"];
}

SuperType.prototype.getSuperValue = function(){
  return this.property
}

function SubType(){
  this.subProperty = false;
}

// 關鍵 建立SuperType的實例,並將該實例賦值給SubType.prototype 
SubType.prototype = new SuperType();

SubType.prototype.getSubValue  = function(){
  return this.subProperty
}

//對象字面量 會覆蓋
// SubType.prototype = {
// methodName() {
// }
// }

var instance1 = new SubType();
console.log(instance1.getSuperValue()) //true 

var instance2 = new SubType();
instance2.colors.push("black");
console.log(instance1.colors)

複製代碼

借用構造函數繼承

定義
  • 在子類型構造函數的內部調用超類型構造函數 使用apply()或call 方法(不使用原型)
缺點
  • 只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法
  • 沒法實現複用,每一個子類都有父類實例函數的副本,影響性能
實現
function SuperType (name){
  this.colors = ["red", "blue", "green"];
  this.name = name;
}

function SubType(){
  // 關鍵點 繼承 SuperType 類 並傳遞了參數
  SuperType.call(this,'Nicholas')
  this.age = 23
}

var instance1 = new SubType();
instance1.colors.push("black");
var instance2 = new SubType();

console.log(instance1.colors)// ["red", "blue", "green", "black"]
console.log(instance2.colors)// ["red", "blue", "green"]

console.log(instance1.name) //Nicholas
console.log(instance1.age)  //23

複製代碼

組合繼承

定義
  • 用原型鏈實現對原型屬性和方法的繼承,用借用構造函數技術來實現實例屬性的繼承。

-有時候也叫作僞經典繼承前端

缺點
  • 調用兩次超類型, 存在兩份相同的屬性/方法,實例和原型上各有一份
實現
function SuperType (name){
  this.colors = ["red", "blue", "green"];
  this.name = name;
}
SuperType.prototype.sayName = function(){
  console.log(this.name)
} 

function SubType(name,age){
  // 關鍵點 繼承 屬性
  SuperType.call(this,name)  //第二次調用
  this.age = age
}

//繼承超類型原型方法
SubType.prototype = new SuperType() //第一次調用

// 重寫SubType.prototype的constructor屬性,指向本身的構造函數SubType 否自指向超類型
SubType.prototype.constructor = SubType; 
SubType.prototype.sayAge = function(){
  console.log(this.age)
}

var instance1 = new SubType('小明',20);
instance1.colors.push("black");
console.log(instance1.colors)// ["red", "blue", "green", "black"]
instance1.sayAge() //20
instance1.sayName() // 小明

var instance2 = new SubType('小紅',21);
console.log(instance2.colors)// ["red", "blue", "green"]
instance2.sayAge() //21
instance2.sayName() //小紅

複製代碼

原型式繼承

定義

利用一個空對象做爲中介,將某個對象直接賦值給空對象構造函數的原型。java

缺點
  • 不能作到函數複用
  • 共享引用類型屬性的值
  • 沒法傳遞參數
實現
function object(obj){
  function F(){}
  F.prototype = obj;
  return new F();
}

var person = {
  name: 'Nicholas',
  friends : ["Shelby","Coury","Van"]
}

var anotherPerson  = object(person)
// 與Object.create 相同 相比之下 Object.create更規範化 
// var anotherPerson = Object.create(person) 
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"
複製代碼

寄生式繼承

定義
  • 寄生式繼承是與原型式繼承繼承緊密相關的一種思路
  • 在原型式繼承的基礎上,加強對象,返回構造函數
缺點(同原型式繼承)
  • 不能作到函數複用
  • 共享引用類型屬性的值
  • 沒法傳遞參數
代碼
function createAnother(original){
  var clone = object(original); // 或 Object.create(original) 
  clone.sayHi = function(){  // 以某種方式來加強對象
    alert("hi");
  };
  return clone; // 返回這個對象
}


var person = {
  name: 'Nicholas',
  friends : ["Shelby","Coury","Van"]
}

var anotherPerson  = createAnother(person) 

anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = createAnother(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");

alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"
複製代碼

寄生組合式繼承

定義
  • 結合借用構造函數傳遞參數和寄生模式實現繼承
  • 經過借用構造函數繼承屬性,經過原型鏈的混成形式繼承方法
  • 使用寄生式繼承來繼承超類型的原型,而後在將結果指定給子類型的原型
實現
function inheritPrototype(subType, superType){
  var prototype =Object.create( superType.prototype); // 建立對象,建立父類原型的一個副本
  prototype.constructor = subType; // 加強對象,彌補因重寫原型而失去的默認的constructor 屬性
  subType.prototype = prototype  // 指定對象,將新建立的對象賦值給子類的原型

}

// 父類初始化實例屬性和原型屬性
function SuperType (name){
  this.name =  name;
  this.colors = ["red", "blue", "green"];
}

SuperType.prototype.sayName = function(){
  alert(this.name);
};

// 借用構造函數傳遞加強子類實例屬性(支持傳參和避免篡改)
function SubType(name, age){
  SuperType.call(this, name);
  this.age = age;
}


// 將父類原型指向子類
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function (){
  alert(this.age)
}


var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);

instance1.colors.push("black"); // ["red", "blue", "green", "black"]
instance2.colors.push("gray"); // ["red", "blue", "green", "gray"]
複製代碼

ES6類繼承extends

定義
  • extends關鍵字主要用於類聲明或者類表達式中,以建立一個類,該類是另外一個類的子類。
  • 一個類中只能有一個構造函數
  • Class 定義的方法 直接掛載到原型上
  • 子類沒有本身的this對象,因此必須先調用父類的super()方法,不然新建實例報錯。
實現
class SuperType {
  constructor(name,age){
    this.age = age;
    this.mame = name;
  }

  
  getAge(){
    return this.age
  }

  getName(){
    return this.name
  }

}

class SubType extends SuperType{
  constructor(name,age,sex){
    //調用超類型 必須在使用「this」以前首先調用 super()。
    super(name,age)
    this.sex = sex
  }
}

var instance = new SubType('渣渣輝',18,'男')

console.log(instance.getAge())
複製代碼

結語

本文介紹的幾種繼承方式 ,基本足夠平常開發使用了, 還有其餘的繼承方式在這裏就先不介紹了. 在學習中,關於繼承方面的知識尤其重要,但願你們好好學習,活學活用,爭作大佬,向大佬們學習.嘿嘿 !!!
複製代碼

參考文章 木易楊說,JavaScript經常使用八種繼承方案app

(前端界的一枚小學生)函數

相關文章
相關標籤/搜索