javascript----繼承模式

我是誰,我來自哪,我是誰的誰

想必大家一定在學習或者開發過程常常被JS獨有的原型繼承撥過不少腦弦吧,為何不迎問題而上,直面解決這些謎團,今天就來總結一下Js的認親問題...

為開發需求選擇一種合適的繼承模式可以提高代碼的可讀性和便于排錯,從而提高我們的開發效率,因而今天就來總結一下ES5之前的繼承模式,ES6之后再進行補充或者另外討論

原型鏈模式-----------------------------------------------所有繼承模式的基礎

關鍵詞: 構造函數 原型對象 實例對象 原型對象為另一類型的實例

function SuperType(){ //超類構造函數 this.property = true; } SuperType .prototype.getSuperValue = function(){ //定義超類的原型方法 return this.property; }; function SubType(){ //父類的構造函數 this.subproperty = false; } SubType.prototype = new SuperType(); //重寫父類的原型對象,繼承超類 SubType.prototype.getSubValue = function(){ //定義父類獨有的原型方法 return this. subproperty; }; var instance = new SubType(); //實例化子類對象 alert(instance.getSuperValue()); //true //調用超類的原型方法 }

原型鏈的問題:

  • 超類的實例屬性變成了子類的原型屬性,無法解決引用類型值被所有實例共享的問題.
  • 創建子類型實例時無法向超類型的構造函數中傳遞參數
    以上問題導致很少單獨使用原型鏈.

借用構造函數-------------------------------------------借用超類構造函數

關鍵詞:借用超類構造函數

function SuperType(){ this.name = name; } function SubType(){ SuperType.call(this,"LiAo"); this.age = 22; } var instance = new SubType(); alert(instance.name); //"Nicholas" alert(instance.age); // 22

借用構造函數的問題

  • 與構造函數模式一樣,無法做到函數復用.
  • 另外此時沒有使用原型鏈,所以子類無法調用超類的原型方法

組合繼承----------------------------------------結合借用構造函數和原型鏈

關鍵詞:
  • 借用構造函數負責實現對實例屬性的繼承
  • 原型鏈負責實現對原型屬性和方法的繼承(復用)
    `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; //子類自身的實例屬性
    }

SubType.prototype = new SuperType(); //通過原型鏈繼承超類
SubType.prototype.constructor = SubType; //恢復constructor的指向
SubType.prototype.sayAge = function(){ //定義父類獨有的原型方法
alert(this.age);
};
var instance = new SubType("LiAo",22);
`
組合繼承模式的優點

  • 主要融合了原型鏈和借用構造函數模式的優點
  • 可以用instanceof 和isPrototypeOf()來識別創建的對象類型
    組合繼承模式的問題
  • 無論在什么情況下,都會調用兩次超類型構造函數,一次是在子類型實例化的時候,第二次是在借用構造函數的時候,導致父類的原型對象會出現超類的實例屬性或方法,解決此問題的辦法先留個懸念....

原型式繼承-------------------------------------------------------敷衍式代孕

關鍵詞:基于已有對象創建新對象 對象關聯 生下就撤

工具函數:
function object(o){ function F(){}; //創建臨時類型 F.prototype = o; //讓臨時類型的原型對象指向傳入的對象(繼承) return new F(); //返回這個臨時類型的實例(返回后就撤!) }
其實仔細觀察這個函數,會發現臨時類型F是起著代孕的作用,受人委托替傳入的媽媽對象生了個寶寶,生完后孩子還沒睜眼就悄然離開,所以寶寶只認當前的媽媽,有著媽媽的各種特征.
用法:
var mom = { name = Lily, hairColor: "black", skin:"white" } var baby = object(mom); baby.name = "Jack"; alert(baby.name) ; //"Jack" alert(baby.skin); //"white"
ES5規范通過Object.create()方法規范化原型式繼承
該函數接收兩個參數:
①用作新對象原型的對象
②為新對象定義額外屬性的對象(可選),格式與Object.defineProperties相同,每個屬性都是通過自己的描述符定義的.
該函數的缺點:只能定義額外屬性,不能定義額外方法

原型式繼承的優點

  • 拋棄了構造函數,而是把繼承簡化為對象之間的關聯
  • 適用于想讓一個對象與另一個對象保持類似的情況下使用

原型式繼承的缺點

  • 通過原型式繼承創建的對象是空對象,只不過是關聯了另一個對象,但是在很多時候,我們需要對新對象進行加強,而這時候雖然可以在新對象增添特有的屬性和方法,但是當我們需要很多個這樣的對象的時候,一個個去增添,就顯得很麻煩和難看,于是下面要將的寄生式繼承可以幫到我們

寄生式繼承----------------------------------------------------負責式代孕

關鍵詞: 增強對象 生完培養一會再撤

function createBaby(mom){ var baby = object(mom); baby.sayHi = function(){ alert("hi!); } return baby; }
看完你大概懂了吧,寄生式繼承類似原型式繼承,只不過在內部對新對象進行增強,這樣通過它產生的對象都是增強式的. 就好像一個負責的代孕媽媽,生完之后還要教會孩子一些技能,等到親媽來了再離開,不過戲劇化的是,這個孩子還是只認親媽(臥槽)
寄生式繼承的優點

  • 解決了上面所提到的問題,可以快速新建一批增強式的對象.

寄生組合式繼承-----------------------------最完美的繼承方式(非最優雅)

關鍵詞:只要超類構造函數的原型對象,不要它本身

相信你還記得上面留下的懸念吧,組合式繼承會二次調用超類構造函數,寄生組合式繼承就是為了解決這個問題的,其配合一個工具函數使用:
function inheritPrototype(subType,superType){ var prototype = object(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); };
雖然寄生組合式繼承是引用類型最理想的繼承范式,但是我還是覺得代碼還是不夠優雅,如果要數優雅程度的話,那就離不開ES6這塊巨型語法糖了

上面介紹了的繼承模式有:

  • 原型鏈

  • 借用構造函數

  • 組合繼承

  • 原型式繼承

  • 寄生式繼承

  • 寄生組合式繼承
    其中原型鏈和借用構造函數模式都有自己比較大的問題,組合繼承把兩者的優點融合在一起了,因此組合繼承比較常見,但是組合繼承也有自己的問題,而這個問題在寄生組合式繼承中得到解決,寄生組合式繼承代碼不是那么的優雅,但是是最理想的方式.
    原型式繼承和寄生式繼承是一對兒,他們都拋棄了構造函數,而選擇一種新的思維來進行繼承------對象關聯,這種方式代碼最優雅.原型式新建立的對象是一個空對象,寄生式新建的對象則是一個增強的對象(用于大量生產).

      個人來說,原型式繼承和寄生式繼承是我比較順眼的模式
      其他模式感覺都是為了使js這么語言向傳統的類繼承靠近的
      其實js的本質就是對象關聯,而原型式繼承和寄生式繼承正體現了這一點
      這兩種繼承各有各的適合情景,原型式繼承適合生產少量的對象后自己再進行增強
      寄生式繼承適合生產大量的有類似功能的對象.
    

下面是我改寫寄生式繼承的一個工具函數
function createAndConnect(original,propertyObject){ var clone = Object.create(original); if(typeof propertyObject == "object"&&propertyObject!=null){ for(var key in propertyObject){ clone[key] = propertyObject[key]; } } return clone; }
多增添了一個用于加強對象的參數,就不用每次都得在內部加強了,而且使用方式顯得相對優雅一點,如:
var chinese ={ country: "China", language:"Chinese", getLanguage: function(){ console.log("我的母語是"+this.language); }, skin: "yellow", aveHeight:1.71, face:["nose","eyes","mouse"] } var chineseStudent =createAndConnect(chinese,{ name:"LiAo", //獨有屬性 height:0.1, //獨有屬性 score: 59, //獨有屬性 secondLanguage:"English", //獨有屬性 skin:"a little yellow", //重寫屬性 getSecondLanguage:function(){ console.log("我的第二門語言是"+this.secondLanguage); } }) console.log(chineseStudent.name); // "LiAo" console.log(chineseStudent.skin); // "a little yellow" console.log(chineseStudent.face); //["nose","eyes","mouse"] chineseStudent.getLanguage(); //我的母語是Chinese chineseStudent.getSecondLanguage(); //我的第二門語言是English

最后的話

在createAndConnect函數(意思是創建和鏈接)的第二個參數中,你可以指定新對象自己的屬性和方法,也可以"重寫"原型對象的屬性和方法,我認為這個才是js原型繼承的精髓即對象關聯.同時我也倡導大家用對象關聯的思維去開發js應用!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容