天天看點

簡單粗暴地了解js原型鍊--js面向對象程式設計

1)人是人他媽生的,妖是妖他媽生的。人和妖都是對象執行個體,而人他媽和妖他媽就是原型。原型也是對象,叫原型對象。2)人他媽和人他爸啪啪啪能生出一堆人寶寶、妖他媽和妖他爸啪啪啪能生出一堆妖寶寶,啪啪啪就是構造函數,俗稱造人。3)人他媽也是由人他媽他媽生的,通過人他媽找到人他媽他媽,再通過人他媽他媽找到人他媽他媽……,這個關系叫做原型鍊。4)人他媽生的人會有人的樣子,妖他媽生的妖會有妖的醜陋,這叫繼承。

原型鍊了解起來有點繞了,網上資料也是很多,每次晚上睡不着的時候總喜歡在網上找點原型鍊和閉包的文章看,效果極好。

不要糾結于那一堆術語了,那除了讓你腦筋擰成麻花,真的不能幫你什麼。簡單粗暴點看原型鍊吧,想點與代碼無關的事,比如人、妖以及人妖。

1)人是人他媽生的,妖是妖他媽生的。人和妖都是對象執行個體,而人他媽和妖他媽就是原型。原型也是對象,叫原型對象。

2)人他媽和人他爸啪啪啪能生出一堆人寶寶、妖他媽和妖他爸啪啪啪能生出一堆妖寶寶,啪啪啪就是構造函數,俗稱造人。

3)人他媽會記錄啪啪啪的資訊,是以可以通過人他媽找到啪啪啪的資訊,也就是說能通過原型對象找到構造函數。

4)人他媽可以生很多寶寶,但這些寶寶隻有一個媽媽,這就是原型的唯一性。

5)人他媽也是由人他媽他媽生的,通過人他媽找到人他媽他媽,再通過人他媽他媽找到人他媽他媽……,這個關系叫做原型鍊。

6)原型鍊并不是無限的,當你通過人他媽一直往上找,最後發現你會發現人他媽他媽他媽……的他媽都不是人,也就是原型鍊最終指向null。

7)人他媽生的人會有人的樣子,妖他媽生的妖會有妖的醜陋,這叫繼承。

8)你繼承了你媽的膚色,你媽繼承了你媽他媽的膚色,你媽他媽……,這就是原型鍊的繼承。

9)你談對象了,她媽讓你帶上房産證去提貨,你若沒有,那她媽會問你媽有沒有,你媽沒有那她媽會問你媽她媽有沒有……這就是原型鍊的向上搜尋。

10)你會繼承你媽的樣子,但是你也可以去染發洗剪吹,就是說對象的屬性可以自定義,會覆寫繼承得到的屬性。

11)雖然你洗剪吹了染成黃毛了,但你不能改變你媽的樣子,你媽生的弟弟妹妹跟你的黃毛洗剪吹沒一點關系,就是說對象執行個體不能改動原型的屬性。

12)但是你家被你玩火燒了的話,那就是說你家你媽家你弟們家都被燒了,這就是原型屬性的共享。

13)你媽外号阿珍,鄰居大娘都叫你阿珍兒,但你媽頭發從飄柔做成了金毛獅王後,隔壁大嬸都改口叫你包租仔,這叫原型的動态性。

14)你媽愛美,又跑到南韓整形,整到你媽他媽都認不出來,即使你媽頭發換回飄柔了,但隔壁鄰居還是叫你金毛獅王子。因為沒人認出你媽,整形後的你媽已經回爐再造了,這就是原型的整體重寫。

尼瑪!你特麼也是夠了! Don't BB! Show me the code!

看完基本能了解了吧?

現在再來說說 p1.age = 20、p1.home = ['Hangzhou', 'Guangzhou'] 和  p1.home[0] = 'Shenzhen' 的差別。 p1.home[0] = 'Shenzhen';  總結一下是 p1.object.method,p1.object.property 這樣的形式。

p1.age = 20;  p1.home = ['Hangzhou', 'Guangzhou'];這兩句還是比較好了解的,先忘掉原型吧,想想我們是怎麼為一個普通對象增加屬性的:

這樣是不是就了解了呢?一樣一樣的呀。

那為什麼 p1.home[0] = 'Shenzhen' 不會在 p1 下建立一個 home 數組屬性,然後将其首位設為 'Shenzhen'呢? 我們還是先忘了這個,想想上面的obj對象,如果寫成這樣: var obj.name = 'xxx', obj.num = [100, 200],能得到你要的結果嗎? 顯然,除了報錯你什麼都得不到。因為obj還未定義,又怎麼能往裡面加入東西呢?同理,p1.home[0]中的 home 在 p1 下并未被定義,是以也不能直接一步定義 home[0] 了。如果要在p1下建立一個 home 數組,當然是這麼寫了:

這不就是我們最常用的辦法嗎?

而之是以 p1.home[0] = 'Shenzhen' 不直接報錯,是因為在原型鍊中有一個搜尋機制。當我們輸入 p1.object 的時候,原型鍊的搜尋機制是先在執行個體中搜尋相應的值,找不到就在原型中找,還找不到就再往上一級原型中搜尋……一直到了原型鍊的終點,就是到null還沒找到的話,就傳回一個 undefined。當我們輸入 p1.home[0] 的時候,也是同樣的搜尋機制,先搜尋 p1 看有沒有名為 home 的屬性和方法,然後逐級向上查找。最後我們在Mother的原型裡面找到了,是以修改他就相當于修改了 Mother 的原型啊。

一句話概括:p1.home[0] = 'Shenzhen'  等同于  Mother.prototype.home[0] = 'Shenzhen'。

由上面的分析可以知道,原型鍊繼承的主要問題在于屬性的共享,很多時候我們隻想共享方法而并不想要共享屬性,理想中每個執行個體應該有獨立的屬性。是以,原型繼承就有了下面的兩種改良方式:

簡單粗暴地了解js原型鍊--js面向對象程式設計
簡單粗暴地了解js原型鍊--js面向對象程式設計

View Code

結果是醬紫的: 

這裡第一次執行的時候,得到 Person.prototype.age = undefined, Person.prototype.hobby = ['running','football'],第二次執行也就是 var p1 = new Person('Jack', 20) 的時候,得到 p1.age =20, p1.hobby = ['running','football'],push後就變成了 p1.hobby = ['running','football', 'basketball']。其實分辨好 this 的變化,了解起來也是比較簡單的,把 this 簡單替換一下就能得到這個結果了。 如果感覺了解起來比較繞的話,試着把腦子裡面的概念扔掉吧,把自己當浏覽器從上到下執行一遍代碼,結果是不是就出來了呢?

通過第二次執行原型的構造函數 Mother(),我們在對象執行個體中複制了一份原型的屬性,這樣就做到了與原型屬性的分離獨立。細心的你會發現,我們第一次調用 Mother(),好像什麼用都沒有呢,能不調用他嗎?可以,就有了下面的寄生組合式繼承。

簡單粗暴地了解js原型鍊--js面向對象程式設計
簡單粗暴地了解js原型鍊--js面向對象程式設計

結果是醬紫的:

原型中不再有 age 和 hobby 屬性了,隻有兩個方法,正是我們想要的結果! 

關鍵點在于 object(o) 裡面,這裡借用了一個臨時對象來巧妙避免了調用new Mother(),然後将原型為 o 的新對象執行個體傳回,進而完成了原型鍊的設定。很繞,對吧,那是因為我們不能直接設定 Person.prototype = Mother.prototype 啊。

說了這麼多,其實核心隻有一個:屬性共享和獨立的控制,當你的對象執行個體需要獨立的屬性,所有做法的本質都是在對象執行個體裡面建立屬性。若不考慮太多,你大可以在Person裡面直接定義你所需要獨立的屬性來覆寫掉原型的屬性。總之,使用原型繼承的時候,要對于原型中的屬性要特别注意,因為他們都是牽一發而動全身的存在。

下面簡單羅列下js中建立對象的各種方法,現在最常用的方法是組合模式,熟悉的同學可以跳過到文章末尾點贊了。

簡單粗暴地了解js原型鍊--js面向對象程式設計
簡單粗暴地了解js原型鍊--js面向對象程式設計

顯然,當我們要建立批量的person1、person2……時,每次都要敲很多代碼,資深copypaster都吃不消!然後就有了批量生産的工廠模式。

簡單粗暴地了解js原型鍊--js面向對象程式設計
簡單粗暴地了解js原型鍊--js面向對象程式設計

 工廠模式就是批量化生産,簡單調用就可以進入造人模式(啪啪啪……

)。指定姓名年齡就可以造一堆小寶寶啦,解放雙手。但是由于是工廠暗箱操作的,是以你不能識别這個對象到底是什麼類型、是人還是狗傻傻分不清(instanceof 測試為 Object),另外每次造人時都要建立一個獨立的temp對象,代碼臃腫,雅蠛蝶啊。

簡單粗暴地了解js原型鍊--js面向對象程式設計
簡單粗暴地了解js原型鍊--js面向對象程式設計

構造函數與C++、JAVA中類的構造函數類似,易于了解,另外Person可以作為類型識别(instanceof 測試為 Person 、Object)。但是所有執行個體依然是獨立的,不同執行個體的方法其實是不同的函數。這裡把函數兩個字忘了吧,把sayName當做一個對象就好了解了,就是說張三的 sayName 和李四的 sayName是不同的存在,但顯然我們期望的是共用一個 sayName 以節省記憶體。

簡單粗暴地了解js原型鍊--js面向對象程式設計
簡單粗暴地了解js原型鍊--js面向對象程式設計

這裡需要注意的是原型屬性和方法的共享,即所有執行個體中都隻是引用原型中的屬性方法,任何一個地方産生的改動會引起其他執行個體的變化。

簡單粗暴地了解js原型鍊--js面向對象程式設計
簡單粗暴地了解js原型鍊--js面向對象程式設計

做法是将需要獨立的屬性方法放入構造函數中,而可以共享的部分則放入原型中,這樣做可以最大限度節省記憶體而又保留對象執行個體的獨立性。

放張美圖調節下~~~碼字不易,順手點贊哈! 下一篇--閉包,再見。

(圖檔出處:小周,轉載請注明)

原創文章,轉載請注明出處!本文連結:http://www.cnblogs.com/qieguo/p/5451626.html 

繼續閱讀