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


簡述引用類型

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

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

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

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

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

至此,除了贊嘆我的排比句是多么盪氣回腸之外,你一定也發現:

  • 引用類型就是一種有聯系方式的數據類型
  • 這種間接關系,使不同變量共享同一數據成為事實

例如

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放的是該原型所屬的函數對象,即每個圖書室里都放在該圖書室所屬老師的聯系方式,比如電話號碼。

  • 小強校長帥嗎?

顏值爆表。


如果你有其它關心的事項,可以發表評論或者聯系我,或者在這里查看最新更改。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM