從我的校長生涯談原型和原型鏈

大眾美男典範發表於2018-08-02

簡述引用型別

關於引用型別的賦值,上篇已經寫過。

如果說引用型別是地點,我們操作的就是它的地址;

如果說引用型別是房子,我們操作的就是它的鑰匙;

如果說引用型別是人物,我們操作的就是它的手機號;

如果說我們不用比喻,我們操作的就是它的引用。

至此,除了讚歎我的排比句是多麼蕩氣迴腸之外,你一定也發現:

  • 引用型別就是一種有聯絡方式的資料型別
  • 這種間接關係,使不同變數共享同一資料成為事實

例如

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可以建立物件。

但是,校長為了學生的多樣化,又培養了語文老師、數學老師、思想品德老師等老師,而且還可以按需要培養更多老師;

同樣,開發者想要建立多樣化的資料、符合需要的物件,諸如StringNumberBoolean這些函式物件也必不可少的,而且也可以根據需要寫各種建構函式。

可以看到,校長培訓出老師,老師再培訓出學生;

Function建立函式物件,函式物件再建立物件;

只不過javascript的培訓方式是new

javascript的圖書室

校長為了避免給每位老師買教學經驗方面的書,所以建立了自己的圖書室,用來讓自己培養的老師共享這些資源;

而我們的Function,也並不想把那些常用的方法都複製一份,儲存到ObjectStringArray...以及後來新建立的N多建構函式當中,於是新增一個屬性prototype(即原型物件),把一些公共的方法存在裡面;

Function讓它建立出來的函式物件共享prototype的方式,就是在通過new Function建立函式物件的同時,會使

被建立的函式物件.__proto__ = Function.prototype
複製程式碼

比如,在建立Object的時候,會使

Object.__proto__ = Function.prototype
複製程式碼

這個場景似曾相識?

沒錯,這就是我小強校長在建立自己的圖書室後,將圖書室鑰匙送給孔仔老師一把的情景。

此後,孔仔老師就可以來我的圖書室,查閱教學經驗相關的書籍。

同理,Object也因此可以訪問Functionprototype,使用Function為他們精心準備的函式物件的方法。

驗證

Object.__proto__ === Function.prototype     // true
複製程式碼

這裡的true表示的就是,鑰匙已拿到,Object已擁有Functionprototype

接下來,可能會更多用到“擁有”這個詞語

為什麼呢?

雖然,根據開篇對引用型別的介紹,可知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就是孔仔老師,Objectprototype就是孔仔老師的圖書室。

為了減少不同函式物件的prototype的重複,我們把很通用的物件的方法都放到Objectprototype中,並通過上述方法讓其它函式都的prototype都擁有它。

這樣,每個物件都擁有函式的prototype,每個函式的prototype又都擁有Objectprototype,那麼每個物件也都擁有Objectprototype,即物件總能找到早就給它們精心準備好的方法的;

不同原型之間這個不依不饒的關係,就是原型鏈。

對於學生來講,他們可以去的辦公的總和、以及先後順序,就相當於我們的原型鏈。

如圖

從我的校長生涯談原型和原型鏈

關於“隧道”的建成,還有一些重要問題:

實際上,被建立的函式物件.prototype.__proto__ = Object.prototype,並非Function做到的,而是Object做到的。

這裡,Object其實是使用的這一規則:

只要我建立了你,你就擁有了我的公共區域

因為javascript的建立方式是new,要想實現被建立的函式物件.prototype.__proto__ = Object.prototype,需要先有

被建立的函式物件.prototype = new Object()
複製程式碼

即所有物件的prototype都是Object建立的,都是Object的例項。

其它函式物件的prototype因此才能擁有Objectprototype,即實現這種效果

被建立的函式物件.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放的是該原型所屬的函式物件,即每個圖書室裡都放在該圖書室所屬老師的聯絡方式,比如電話號碼。

  • 小強校長帥嗎?

顏值爆表。


如果你有其它關心的事項,可以發表評論或者聯絡我

原文連結

相關文章