簡述引用型別
關於引用型別的賦值,上篇已經寫過。
如果說引用型別是地點,我們操作的就是它的地址;
如果說引用型別是房子,我們操作的就是它的鑰匙;
如果說引用型別是人物,我們操作的就是它的手機號;
如果說我們不用比喻,我們操作的就是它的引用。
至此,除了讚歎我的排比句是多麼蕩氣迴腸之外,你一定也發現:
- 引用型別就是一種有聯絡方式的資料型別
- 這種間接關係,使不同變數共享同一資料成為事實
例如
var a = {n: 1}
複製程式碼
用變數a
儲存了{n: 1}
的引用,通過這個引用可以操作{n: 1}
,這個引用就是聯絡方式。
var b = a
複製程式碼
將a
的引用賦值給b
,變數b
也儲存了{n: 1}
的引用,也可以操作{n: 1}
,這就是共享。
好比,你和你的房間的聯絡方式,就是房鑰匙。
因為你有房鑰匙,所以你才能夠進房間,操作房間裡面的東西。
如果路人甲默默複製一把,路人甲就可以和你一樣,能夠操作房間裡的東西,這就是共享。
問題來了————
你倆雖然有你房間的鑰匙,但是你倆擁有這個房間嗎?
答案是肯定的。
即使是間接擁有,也是擁有。
好了,明白了上面的東西,原型就不是問題了。
我的校長生涯
在表達我對原型的理解之前,我想先講一個發生在我身上的不真實的故事。
接下來,我將講述我的一次創辦學校的經歷。
階段一、白手起家
回到多年前。
我是小強,此時我正打算建立一所學校,所以大家也可以叫我小強校長。
首先,我要培養一個老師來替我上課,因為作為一個校長,我還有很多其它事情要做。
很快,我將多年的教學經驗傳授給一個叫孔仔的人,培養出第一個老師。
後來呢,孔仔也培養出一批又一批的學生。
階段二、學科多樣化
學校算是建成,孔仔也能完成教學任務,不斷培養學生。
但是我發現一個問題,一個人的力量畢竟有限,雖然孔仔能完成基本教學,卻沒有精力在每個學科上做到專精。
這就導致,培養出來的學生沒有專長,大多很普通。
終於有一天,我的學校得到許多好心人的贊助,我當時表示力度大點十分感謝。
錢多了,我就可以培養出更多的老師,不同特色的老師又可以培養出不同特色的學生,這不正是我的畢生所追求的東西嗎?
於是,我的學校除了孔仔老師,又有了語文老師、數學老師、思想品德老師......
而且我還可以培養更多學科的老師。
階段三、建設圖書室
不知何時開始,有一些老師會找我申請一些教學方法的書,這我是十分支援的,可以說是有求必應。
隨著申請的老師越來越多,我總結了一些很多老師會用到的教學方法的書,於是我就想:
不如我在自己辦公室旁邊建設一個圖書室,把這些常用的書放在裡面,老師們想看的時候來這裡看不就行了。
很快有老師向我反映,他們其實也有相同的困擾,學生也會向他們申請一些課程相關的書,而且經常是相同的。
於是我決定,只要是老師,都要有一個自己的圖書室,存放自己學生通常會用到的書或器材。
我也是老師,我是老師的老師。
所以,各科老師的圖書室一般都存放各自文化知識方面的教材,而我的辦公室存放的是教學經驗方面的教材。
馬上就要開工了!
可是我又發現,像《小學生必讀》這類書,幾乎在每個老師的辦公室都有,我想:
不如把這類全校學生都讀的書,放在同一個地方吧,這樣就可以省下更多錢吃喝玩樂建設學校。
我第一想到的,就是孔仔老師,孔仔老師畢竟是我們學校的元老,同時他教的內容是最寬泛的、最不專門的,圖書室應該相對空曠,所以就把《小學生必讀》這類幾乎所有學生都會看的書籍統一放到他的圖書室吧。
於是我決定,在給每個老師建造圖書室的同時,都建造一條隧道通往孔仔老師的圖書室。
我的圖書室也是那時候建的,所以我的圖書室也有一條通往孔仔老師的隧道。
這樣,我培養出來的老師,想看教學經驗方面的書籍,就可以到我的圖書室。
而我校老師培養出來的學生,想看自己學習方面的書籍,就可以到自己老師的圖書室;
如果沒有的話,就可以通過自己老師的圖書室裡的隧道,來到孔仔老師的圖書室,看有沒有想看的書籍。
這樣我的學校就完美了,小強校長還是挺不錯的哈?
原型和原型鏈
先把圖放在這裡。
javascript的培訓方式
在javascript中,Function
扮演的就是校長的角色。
首先,他不想親自去培養學生,所以他培養出了第一個老師孔仔。
Object
就相當於孔仔一樣可以培養出學生,即通過new Object
可以建立物件。
但是,校長為了學生的多樣化,又培養了語文老師、數學老師、思想品德老師等老師,而且還可以按需要培養更多老師;
同樣,開發者想要建立多樣化的資料、符合需要的物件,諸如String
、Number
、Boolean
這些函式物件也必不可少的,而且也可以根據需要寫各種建構函式。
可以看到,校長培訓出老師,老師再培訓出學生;
Function
建立函式物件,函式物件再建立物件;
只不過javascript的培訓方式是new
。
javascript的圖書室
校長為了避免給每位老師買教學經驗方面的書,所以建立了自己的圖書室,用來讓自己培養的老師共享這些資源;
而我們的Function
,也並不想把那些常用的方法都複製一份,儲存到Object
、String
、Array
...以及後來新建立的N多建構函式當中,於是新增一個屬性prototype(即原型物件),把一些公共的方法存在裡面;
Function
讓它建立出來的函式物件共享prototype
的方式,就是在通過new Function
建立函式物件的同時,會使
被建立的函式物件.__proto__ = Function.prototype
複製程式碼
比如,在建立Object
的時候,會使
Object.__proto__ = Function.prototype
複製程式碼
這個場景似曾相識?
沒錯,這就是我小強校長在建立自己的圖書室後,將圖書室鑰匙送給孔仔老師一把的情景。
此後,孔仔老師就可以來我的圖書室,查閱教學經驗相關的書籍。
同理,Object
也因此可以訪問Function
的prototype
,使用Function
為他們精心準備的函式物件的方法。
驗證
Object.__proto__ === Function.prototype // true
複製程式碼
這裡的true
表示的就是,鑰匙已拿到,Object
已擁有Function
的prototype
。
接下來,可能會更多用到“擁有”這個詞語
為什麼呢?
雖然,根據開篇對引用型別的介紹,可知Object.__proto__ = Function.prototype
所做的事情:
無非就是,Function
把公共的方法都放在某個房間裡,再將鑰匙存在自己的屬性prototype
裡;
在賦值時,就是複製了一把prototype
裡的鑰匙,然後存在Object
的屬性__proto__
中。
從這個過程可以看出,原型也不過是引用型別的賦值,就是通過一種聯絡方式間接擁有某個東西。
本篇文章開始說過,
即使是間接擁有,也是擁有。
首先,對引用型別的及其賦值的理解是必要的。
但是,在理解原型和原型鏈過程中,可以不必太關注引用型別賦值過程這種細節。
因為原型的目的,就是讓例項們都擁有有一個公共區域,方便使用一些常用的方法。
所以類似Object.__proto__ === Function.prototype
這種嚇人的結構,它要表達的不過就是這個意思:
前者已經擁有了後者提供的公共區域。
就像我的校長生涯那樣,當我發現建圖書室的作用之後,並不止為自己培養的老師建了圖書室。
只要是老師,都要有一個自己的圖書室,存放自己學生通常會用到的書或器材
這樣,把一些學生的教材也變成共享,就又免得給每個學生都重複買教材。
也就是,不僅Function
建立函式物件時,會
被建立的函式物件.__proto__ = Function.prototype
複製程式碼
而且函式物件在建立物件時,會
被建立的物件.__proto__ = 建立物件的函式物件.prototype
複製程式碼
總結一下,只要new
的時候,就會
例項.__proto__ = 建立者.prototype
複製程式碼
即只要我建立了你,你就擁有了我的公共區域。
javascript的隧道
回顧我的校長生涯,在我即將開工給我和每位老師建圖書室之前,我又想到:
每個老師的圖書室裡的書,也有很多是重複的,不如把這些重複的都放到元老級教師孔仔的圖書室吧。
可是學生只能進各自老師的圖書室,怎麼讓他們也能進孔仔老師的圖書室呢?
還記得睿智的小強校長是怎麼做的嗎:
在建每件圖書室的同時,修一條隧道可以到達孔仔老師的圖書室,即Function建立物件的同時會
被建立的函式物件.prototype.__proto__ = Object.prototype
複製程式碼
例如
Array.prototype.__proto__ === Object.prototype // true
複製程式碼
沒錯,對於javascript
來說,Object
就是孔仔老師,Object
的prototype
就是孔仔老師的圖書室。
為了減少不同函式物件的prototype
的重複,我們把很通用的物件的方法都放到Object
的prototype
中,並通過上述方法讓其它函式都的prototype都擁有它。
這樣,每個物件都擁有函式的prototype
,每個函式的prototype
又都擁有Object
的prototype
,那麼每個物件也都擁有Object
的prototype
,即物件總能找到早就給它們精心準備好的方法的;
不同原型之間這個不依不饒的關係,就是原型鏈。
對於學生來講,他們可以去的辦公的總和、以及先後順序,就相當於我們的原型鏈。
如圖
關於“隧道”的建成,還有一些重要問題:
實際上,被建立的函式物件.prototype.__proto__ = Object.prototype
,並非Function做到的,而是Object做到的。
這裡,Object
其實是使用的這一規則:
只要我建立了你,你就擁有了我的公共區域
因為javascript的建立方式是new
,要想實現被建立的函式物件.prototype.__proto__ = Object.prototype
,需要先有
被建立的函式物件.prototype = new Object()
複製程式碼
即所有物件的prototype
都是Object
建立的,都是Object
的例項。
其它函式物件的prototype
因此才能擁有Object
的prototype
,即實現這種效果
被建立的函式物件.prototype.__proto__ = Object.prototype
複製程式碼
那麼,如果你是類比我的校長生涯來理解原型的,你就會想:
new在故事中不是“培訓”的意思嗎,這是不是說,其它的圖書室都是孔仔“培訓”出來的?
其實,這裡我們自圓其說靈活理解就行了,畢竟例子只是用來幫助理解的。
所以,我們的“new”在這時候就是“建立”的意思。
在javascript中,所有物件的prototype
都是Object
建立的,那麼
在我的校長生涯中,故事可能就是這樣的:
我的校長生涯後記
這個時刻,學校還只是我(小強校長)和孔仔兩個人。
我說,孔仔,為了實現資源的共享,我有一個想法。
孔仔說,啥想法?
我說,把你培養出來後,我已經很累了,但是我們這個學校將來肯定會得到好心人的捐助,也一定會培養更多的老師,老師們也一定需要教學經驗方面的學習素材。如果每人我都發一套的話,就有點貴。所以我想給自己建造一個圖書室,專門放這些資料,這樣不管是你,還是以後培養出來的老師,就都可以在這裡共享這些資源了。你覺得怎樣,孔仔?
孔仔說,小強校長真摳門英明啊!您看這樣如何,每個老師也都建設一個自己的圖書室,這樣,很多給學生的教材就不用重複買了,他們想用想看的時候去老師的圖書室裡找就行了,更省錢。
我說,只給學生們開一個圖書室不可以嗎,每個老師都有圖書室會不會浪費?
孔仔說,不太好吧,畢竟不同學科的學生,使用教材的差異還是挺大的,不是很通用,還是建議每個老師都有各自的圖書室,方便管理。
我說,有道理,但是總有一些通用的教材,比如《小學生必讀》這種,沒必要每個老師的圖書室裡都放一套,不夠省錢。
孔仔說,您的意思是?
我說,放你那裡吧。
孔仔已經跟不上我的思路,問,其他老師的學生都是去各自老師的圖書室啊,這樣只有我的學生能看到《小學生必讀》這類書吧?
我說,這還不簡單,每個老師的圖書室都修一條隧道通向你的圖書室。
孔仔沉默。
我說,修圖書室的事情,就由你來負責吧!先給本校長來一個圖書室吧。
孔仔說,不能,我要先給自己修建一個圖書室,否則給你修建的時候不知道隧道通向哪裡。
我說,好吧。
從此,每當我培養出一個老師,孔仔就幫忙修建一個圖書室,同時挖一條隧道通往他自己的圖書室。
我們的學校也越來越好。
其它你可能關心的事項
- Function.prototype.__proto __ === Object.prototype ?
對。建設每個圖書室的時候,孔仔都挖隧道通向自己的辦公室了,包括校長的辦公室。
- Function.prototype.__proto === null ?
對。我們說好把通用資源都放在孔仔辦公室,如今已經來到孔仔辦公室,還想去哪裡?
- 先有的Function還是先有的Object?
先有的Function。孔仔是我培養出來的,當然是先有的本校長。
- 先有的Function.prototype還是先有的Object.prototype?
先有的Object.prototype。不然孔仔修建圖書室的時候,怎麼知道把隧道通向哪裡。
- constructor是什麼?
原型的constructor放的是該原型所屬的函式物件,即每個圖書室裡都放在該圖書室所屬老師的聯絡方式,比如電話號碼。
- 小強校長帥嗎?
顏值爆表。
如果你有其它關心的事項,可以發表評論或者聯絡我。