Js原型鏈解讀

前言

在JavaScript中沒"子類”和“父類”的概念,進一步地也沒有“類”和“實例”的的區分。它靠一種看上去十分古怪的”原型鏈“(prototype chain)模式來實現繼承。學過JAVA等編程語言的人可能會認為這是對Java等語言的繼承實現方式的一種拙劣并且失敗的模仿,然而事實并非如此,原型鏈模式和我們常見的Class模式分別是兩種編程范式prototype_base和class_base的實現,前者在動態語言中似乎十分常見,而后者主要在靜態語言領域流行。下面是維基百科關于prototype_base模式的介紹:

Prototype-based programming is a style of object-oriented programming in which behaviour reuse (known as inheritance) is performed via a process of reusing existing objects via delegation that serve as prototypes. This model can also be known as prototypal, prototype-oriented, classless, or instance-based programming. Delegation is the language feature that supports prototype-based programming.
Prototype object oriented programming uses generalized objects, which can then be cloned and extended. Using fruit as an example, a "fruit" object would represent the properties and functionality of fruit in general. A "banana" object would be cloned from the "fruit" object, and would also be extended to include general properties specific to bananas. Each individual "banana" object would be cloned from the generic "banana" object. Compare to the class-based paradigm, where a "fruit" class (not object) would be extended by a "banana" class

維基原文

如何理解原型鏈

我們以一個名字叫Foo()的函數為例。我們定義:

function Foo(){


}

然后再var f1 = new Foo(),var f2 = new Foo(),這期間都有什么事情發生呢?我們通過一張圖來看一下:

prototype.jpg

先介紹兩個概念:_proto_prototype:

  • _proto_:引用《JavaScript權威指南》中的說明:

Every JavaScript object has a second JavaScript object (or null ,
but this is rare) associated with it. This second object is known as a prototype, and the first
object inherits properties from the prototype.
就是說就是每個JS對象一定對應一個原型對象,并從原型對象繼承屬性和方法。既然有這么一個原型對象,那么對象怎么和它對應的?如何描述這種對應關系?答案就是通過_proto_,對象__proto__屬性的值就是它所對應的原型對象。

  • prototype: 與_proto_不同,prototype是函數才有的屬性。當你創建函數時,JS會為這個函數自動添加prototype屬性,值是空對象。而一旦你把這個函數當作構造函數(constructor)調用(即通過new關鍵字調用),那么JS就會幫你創建該構造函數的實例,實例繼承構造函數prototype的所有屬性和方法(實例通過設置自己的__proto__指向承構造函數的prototype來實現這種繼承)。它的存在主要是為了存放共享的數據和實現繼承。

??下面結合上面的圖示來分析,我們可以看到function Foo()對應一個Foo.prototype的原型,那么function FooFoo.prototype之間的關系是什么尼?
??圖里其實已經展示得很清楚了,functon Foo()Foo.prototype的構造函數,Foo.prototypefunction Foo()的原型實例。當我們使用new關鍵字創建var f1 = new Foo(),var f2 = new Foo()后,f1、f2中會有一個_proto_字段指向Foo.prototype,這種xxx._proto_._proto....的指向就代表了原型鏈的結構(應該是個森林)。同時每個函數function xxx()其實都是通過function Function()來創造的,所以function Foo()_proto_應該指向Function.prototype,并且function Function()自身的_proto_也指向Function.prototype
??事實上,所有function xxx()_proto_最終都會指向Function.prototype,而所有的xxx.prototype最后都會指向Object.prototype,最終指向null。關于function Object()這個函數其實有點像Java中的Object對象,所有原型都會繼承自它的原型。這里有個有意思的問題,function Function()也是個函數,所以function Function()_proto_屬性的值為Function.prototype,這也就意味著它自己創造了自己。這樣的結果就是function Object()._proto_ = Function.prototype、而function Function()._proto._proto_ = Object.prototype,即Object instanceof Function == trueFunction instanceof Object == true翻譯過來就是ObjectFunction的實例,FunctionObject的實例,這是一種類似先有雞還是先有蛋的蜜汁尷尬局面。

總結:

  • 所有對象的_proto_字段都指向創建它的構造函數的原型, 最終都指向Object.prototype,類似xxx.prototype._proto_._proto_..._proto_ = Object.prototype = null就是原型鏈。
  • 所有函數都由function Function()創建,所以所有函數的(包括它本身)_proto_字段都會指向Function.prototype,最后才指向Object.prototype

使用原型鏈實現繼承

定義父函數:

function Father() {
    this.age = "56"; }

Father.prototype.say = function () {
    alert("my age is "+this.age); 
} 

定義子函數:

function Son() {
    this.age = '26';
  this.play = "football"; }

Son.prototype.play = function () {
    alert("I like play "+this.play);
 }

實現繼承后的原型鏈應該是:Son.prototype._proto_ = Father.prototype
實現方式:借用第三個函數過渡

function extends(Child,Father){
    var F = function(){};
    F.prototype = Father.prototype;
    //Child.prototype._proto_ = F.prototype = Father.prototype
    Child.prototype = new F();
    //原本Child.prototype.constructor = F,修改為Child
    Child.prototype.constructor = Child;
    
}

測試驗證:Son的實例可以調用say()則說明繼承成功。

    function Father() {
    this.age = "56"; }

    Father.prototype.say = function () {
    alert("my age is "+this.age); }

    function Son() {
    this.age = '26';
    this.play = "football"; }

    Son.prototype.play = function () {
    alert("I like play "+this.play); }

    function excents(Child,Father) {

    var F = function () {}
    F.prototype = Father.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;   }

    excents(Son,Father);  

    var son = new Son(); 
    son.say();

運行結果:


image

繼承成功!

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

推薦閱讀更多精彩內容