JavaScript進階(五):原型的作用、原理、用途

接下來,我們要說一個很重要的東西,就是原型,也就是 prototype。

原型這個東西在 js 裏面是非常有用的一個東西,也非常的重要。

對於前端來說,原型肯定不會陌生。

但是有幾個問題:這玩意到底是幹啥的?它的原理是什麼?都用在哪裏?

 

首先,這裏用一句話特別明確的告訴大家:

原型這個東西,它可以給類添加或修改東西,這樣的話,這個類它所有的實例就都會有這個東西,這是它的根本作用。

那麼我們就直接來一個例子看看:

可以看到,當我們在數組的原型上面加了一個 a = '123' 之後,它就有了。

最厲害的是,以後我再蹦出來一些別的數組實例,只要它還是個數組,那它上面就也會有這個 a:

這個就是原型的作用,它可以給類添加東西,添加完之後,這個類所 new 出來的,所有實例上面都有這個東西。

 

那麼現在我們就有一個問題,怎麼做到的,它的原理是什麼?

它的原理其實非常的簡單,就是在你這個實例需要某個東西的時候(這個東西可以是個屬性,也可以是個方法),它是這樣的一個順序:

首先,從自己身上找, 如果自己身上有,那就直接拿來用。如果沒有,它會繼續去我的這個類身上找。如果類身上有,那自然就好。如果還沒有,它還會再去父類的原型上面試着找一下。如果還沒有,在往上找,一直找到最後,能找到 Object.prototype 上,這是它最終的一個歸宿(因爲 Object 其實是所有人間接的祖宗,它是最上面的)。一直找到 Object 身上,如果還沒有,不好意思,undefined,沒找到就是 undefined。

說白了,先在自己身上找,沒有就找它爹要,找他爹其實就是在找它爹的原型,還沒有,就找它爺爺,一直找到 Object 身上,還沒有,就是 undefined。

 

既然瞭解了原型,那我什麼時候會用到它?可以用它來幹啥?

以前的時候可能還會用的多一點,現在有專門的class了,方法直接寫裏面,那還要原型幹啥?

當然有用,用途也非常的簡單,就是給類去添加方法。

一般情況下,分成 2 種用途:

1,添加一些公共的方法。

假設我現在有一個方法,它的作用是統計一下我這個字符串裏面有幾個 a,那麼注意,我有兩種方法來做這個事:

首先第一個方法,我可以把它封裝成一個函數:

這種方法是可以的,但是有 2 個問題:

1,太囉嗦了。人家每次用的時候都是括號羅括號,如果層級深一點,變量名長一點,看起來就一大堆,很麻煩。

2,你直接把 function countA(){} 這個函數給露在全局外面,這個時候其實很容易重名的。

所以第二種方法可以這麼來寫,我們可以直接把它扔到原型上面去:

可以看到,一樣的可以去解決問題。

並且,在用法上 str.countA() 比 countA(str) 用起來比較方便和自然。

而且最重要的是,不容易重名。因爲如果是一個全局的變量,那就很容易重名。

比如現在這個是統計字符串的 a,如果我還有一個 countA 是用來統計數組有幾個 a 的呢?

這樣就不會重名。

所以,原型的第一種用途就是,可以去給一些類,不管是系統類,還是你自己的類,去添加一些公共的方法。

 

然後第二種用途就是,可以去修補系統的函數。

什麼意思呢?

這種用法其實用的還蠻多的,有人給它起了個專門的名詞叫 polyfill,補充系統函數的功能。

相信大家經常看到 polyfill 這個詞,其對應的中文也有很多,比如適配器,墊片等等。剛開始的時候百思不得其解,啥玩意啊?

其實說白了,polyfill 就是兼容。

比如 map 函數在高級瀏覽器中是沒問題的:

可以看到,這個結果在谷歌瀏覽器上面是 OK 的。

但是,低級瀏覽器是不認識 map 的,它是 ES6 纔出現的函數,比如 IE:


那麼如果我們用了這種方法之後,是不是在低級瀏覽器上也能使用 map 了:

就是這麼簡單。

當然這時候還有個問題,就是我們自己實現的方法,雖然說功能是一致的,但是它的性能遠不如原生提供的方法來的高。

所以,我們可以這麼寫:

說的直白點,如果本身你就有 map,那就用系統那套,因爲系統那套性能高。

如果沒有,Array.prototype.map 是 undefined,那我就用後面自己實現的這個。

這樣的話,既照顧了低級瀏覽器,高級瀏覽器下面也還是用的系統那套,性能不會受到影響。

這個就叫 polyfill,也是原型的一種用法。

 

到現在,我們基本上來說,就算是理解了原型各種各樣的一些東西,那麼我們來總結一遍:

原型在以前的版本當中,其實它更主要的是幫我們來實現這個類本身。

而現在,我們有了 class 之後,理論上,在我寫這個類的時候,其實是用不着原型了,但是原型它自己也有很大的作用。

原型的作用其實非常的簡單,就是給這個類去添加方法。

它不是去給某一個實例加,它是給類加東西,加完之後,所有的實例它都會有。

當然這裏面我們不光要了解它的一個作用,我們也得知道它爲什麼能起這個作用,這個也是一件很重要的事。

這個過程其實特別的簡單,當然這個過程不用我們來完成,都是由 js,由語言自身來支撐這些功能的,不用我們來做。

就是說它其實會往上找,就這三個字,就能體現它這功能的原理。

說白了就是,它會先去找實例本身,如果有,那自然最好。如果沒有,沒關係,我可以找實例所對應的那個類,它的原型,然後找它的原型上有沒有。如果還沒有的話,它還會繼續往上再來找,這樣的一個過程。

所以說原型這個東西,其實也並不複雜。

然後原型的功能,或者說我們什麼時候去用它,它一般來說有 2 個大用途:

第一個,我可以去給這個類去添加一些公共的方法。

第二個,給系統類去打補丁。你有就用你的,因爲系統自帶的,肯定性能最高,沒有就再用我這個。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章