四、js實現(xiàn)繼承的幾個方法

1. 原型鏈

原型鏈是實現(xiàn)繼承的主要方法,它是利用原型,讓一個引用類型繼承另一個應用類型的屬性和方法。

  • 實現(xiàn)原型鏈的基本模式:
//定義父類構(gòu)造函數(shù)
function Person(){
 this.PersonImprint = "from_Person";
}
Person.prototype.PersonSay = function(){
    console.log(this.PersonImprint);
}
//定義子類構(gòu)造函數(shù)
function Son(){
  this.SonImprint = "from_Son";
}
//初始化子類構(gòu)造函數(shù)原型為父類實例----實現(xiàn)繼承父類屬性和方法。
Son.prototype = new Person();
var sonExample = new Son();
console.log(sonExample.PersonImprint)  //from_Person
sonExample.PersonSay())                //from_Person
console.log(sonExample.SonImprint)     //from_Son

上面將Son的原型指向了Person的實例,這樣Son的新原型不僅具有Person的實例所擁有的全部屬性和方法,而且其原型內(nèi)部還有一個指針,指向了Person的原型。
最終得出:sonExample指向Son的原型,而Son的原型又指向Person的原型。

//實例檢測
sonExample instanceof Son        //true
sonExample instanceof Person   //true
sonExample instanceof Object    //true
//原型檢測
sonExample.prototype.isPrototypeOf(Son)   //true
sonExample.prototype.isPrototypeOf(Person)   //true
sonExample.prototype.isPrototypeOf(Object)   //true

由于原型鏈的關(guān)系,可以說sonExampleSon、Person、Object中任何一個類型的實例。

  • 原型鏈注意事項
  • 子類有時候需求覆蓋超類型中的某個方法,或者添加超類型中的某個不存在的屬性或方法,這種操作代碼,需要放在繼承(替換原型)之后。
  • 實現(xiàn)繼承時,不能以對象字面量創(chuàng)建原型,這樣會重寫原型。
  • 原型鏈的問題
  • 依據(jù)原型的“共享”這一點看出的,雖然說是通過原型來實現(xiàn)繼承,但是其原型其實是另一個類型的實例。這樣原來的實例屬性也就成為了現(xiàn)在原型的屬性了。
  • 在創(chuàng)建子類的實例時,不能向超類的構(gòu)造函數(shù)中傳遞參數(shù)。


2. 借用構(gòu)造函數(shù)

這種方法的基本思想相當簡單,即在子類型構(gòu)造函數(shù)的內(nèi)部通過call()和apply()調(diào)用超類型構(gòu)造函數(shù)。

function SuperType(){
 this.colors = ["red","blue","green"];
}
function SubType(){
   SuperType.call(this)
}
var instance1 = new SubType();
instance1.colors.push("black");
//["red","blue","green","black"];
var instance2 = new SubType();
//["red","blue","green"];

上面子類的構(gòu)造方法SubType“借調(diào)”了超類SuperType的構(gòu)造函數(shù),在創(chuàng)建新的實例過程中,運行了超類構(gòu)造函數(shù),這樣一來子類就擁有了超類函數(shù)中定義的所有屬性了。

  • 傳遞參數(shù)
function SuperType(name){
   this.name = name;
}
function SubType(){
   SuperType.call(this,"余嘉")
}
var instance1 = new SubType()
  • 借用構(gòu)造函數(shù)的弊端
  • 如果是僅僅借用構(gòu)造函數(shù)(超類),那么構(gòu)造函數(shù)(超類)的存在意義就是問題所在,因為方法都在超類中定義,因此構(gòu)造函數(shù)的復用就無從談起了。
  • 超類中給原型定義的方法,對于子類型而言是看不見的。

3. 組合繼承(原型鏈+借用構(gòu)造函數(shù))

原型鏈借用構(gòu)造函數(shù)組合使用,利用兩者的長處。

function superType(name){
   this.name = name;
   this.colors =  ["red","blue","green"];
}
superType.prototype.sayName = function(){
   console.log(this.name)
}
funtionc subType(name,age){
   superType.call(this,name);
   this.age = age;
}
subType.prototype = new superType();
subType.prototype.constructor = subType;
subType.prototype.sayAge = function(){
    console.log(this.age)
};
var instance1 = new subType("余嘉",27);
//subType {name: "余嘉", colors: Array(3), age: 27};
instance1.sayAge()  //   27
instance1.sayName()  //   "余嘉"

組合繼承避免了原型鏈和借用構(gòu)造模式的缺陷,融合了他們的優(yōu)點,是項目中最常用的繼承模式。

4. 原型式繼承(Object.create( obj , newKeyobj)

借助原型可以基于已有的對象(實例)創(chuàng)建新對象,同事還不必因此創(chuàng)建自定義類型。

function create(0){
    function F(){}
    F.prototype = o;
    return new F();
}

create()函數(shù)內(nèi)部,先創(chuàng)建一個臨時性的構(gòu)造函數(shù),然后將傳入的對象O作為這個構(gòu)造函數(shù)的原型(淺復制),然后返回臨時構(gòu)造的實例。

es5新增的Object.create(obj , newKeyobj)規(guī)范這個原型式繼承,它接受兩個參數(shù)

  • (必須的)obj 作為新對象的原型對象
  • (可選的)為新對象定義額外屬性對象,和Object.difineProperties()方法的參數(shù)一樣。
var person = {
    name : "余嘉",
    friends:["cat","dog"]
}
var otherPerson1 = Object.create(person);
otherPerson1.name = "小微";
otherPerson1.friends.push("蘿卜");
var otherPerson2 = Object.create(person);
otherPerson1.name = "達令";
otherPerson1.friends.push("白菜");
console.log(person.friends);
//["cat","dog","蘿卜","白菜"]
var person = {
    name : "余嘉",
    friends:["cat","dog"]
}
var otherPerson1 = Object.create(person,{
     name:{
      value:"小微"
     }
});
  • “共享”的利與弊,永遠是原型模式的烙印。

5. 寄生式繼承

寄生式繼承的思路與寄生構(gòu)造函數(shù)和工廠模式類似,創(chuàng)建一個經(jīng)用于封裝繼承過程的函數(shù)。

function createAnother(original){
  var clone  = Object(original);
  clone.sayHi = function(){
      console.log("Hi")    
   };
  return clone
 }

調(diào)用

var person = {
  name:"余嘉",
  friends:["Shelby", "Court", "Van"] 
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi();
//Hi
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容