JavaScript創建對象(三)——原型模式

在JavaScript創建對象(二)——構造函數模式中提到,構造函數模式存在相同功能的函數定義多次的問題。本篇文章就來討論一下該問題的解決方案——原型模式。

首先我們來看下什麼是原型。我們在創建一個函數時,這個函數會包含一個屬性prototype,這個屬性是一個指針,它指向一個對象——該函數的原型對象,這就是原型,它包含了該函數類型的所有實例可共享的屬性和方法,見下面示意圖:

JavaScript創建對象(三)——原型模式

如圖所示,聲明瞭一個函數Person。在JavaScript中,一個函數被聲明的同時就具有了一些屬性,其中有一個叫做prototype,它指向了該函數的原型對象,即上述示例中的Person Prototype。同時,這個原型對象有一個叫做constructor的屬性反過來又指向了該函數對象。

當我們創建一個函數的實例時,例如上面的var personObj = new Person('張三', 12);,這個實例也會有一個屬性指向該函數的原型對象,在Chrome的開發工具中顯示為__proto__。

上面我們說原型的屬性可以被該函數類型的所有實例所共享,那具體是怎麼實現呢?看下面的示例:

JavaScript創建對象(三)——原型模式

在上面的代碼中,我們並沒有給實例添加name屬性和sayName方法,但是依然可以通過實例調用,貌似實例天生就具有了原型的屬性和方法,其實不是的,下面是在Chrome的開發工具中看到的內容:

JavaScript創建對象(三)——原型模式

我們看到,p1是Person類型的,我們給p1設置了age屬性,這裡也能看到age是18。另外我們看到p1有個__proto__屬性,這個就是我們在原型示意圖中說的指向原型對象的屬性。

代碼讀取對象實例某個屬性的時候會執行一次搜索,首先搜索對象實例,如果搜索到了就返回,如果沒有則會繼續搜索__proto__指向的原型對象,搜索到了就返回。所以上面例子中p1.age是搜索到了p1的age屬性返回了,p1.name是搜索到Person Prototype的name返回了,p2.age在Person Prototype中也沒搜到,於是返回了undefined。這就是實例對象共享原型屬性的原理。

除了上面的寫法,原型還有一種更簡單的定義方式,就是用一個包含所有屬性和方法的對象字面量來重寫整個原型對象,這樣避免了每當給原型添加一個屬性就要書寫一遍Person.prototype的繁瑣,同時從視覺上看也更好地封裝了原型的功能,如下代碼所示:

JavaScript創建對象(三)——原型模式

現在回到文章一開始提出的相同功能的函數定義多次的問題,因為函數原型的屬性和方法可以由所有實例所共享,所以只要在原型中定義一次,所有實例就都可以使用,這樣就完美解決了構造函數模式的問題。

總結一下,與構造函數模式相比:

  1. 原型模式不必在構造函數中定義屬性和方法,而是直接定義在原型中。
  2. 這些屬性和方法被所有實例共享。
  3. 想學習更多java知識的朋友可以進群:874811168 一起學習 還有全套的免費資料領取

原型模式雖然好用,但也不是沒有缺點。首先,它省略了為構造函數傳遞初始化參數這一環節,結果所有實例在默認情況下都將取得相同的屬性值。其次,最大的問題是由原型的共享本性帶來的,下面來分析一下原型的共享問題。

通過共享,我們解決了構造函數模式相同功能的函數定義多次的問題,所以共享對於函數是有好處的。對於基本類型的屬性,如上面的name、age,因為屬性的搜索機制是從實例到原型,所以可以通過給實例添加一個同名的屬性,屏蔽掉原型中相應的屬性,問題也不大。然而,對於引用類型的數據來說,問題就比較嚴重了。來看下面的示例:

JavaScript創建對象(三)——原型模式

如上所示,Person.prototype包含了一個引用類型,數組friends,其中friends只是一個指針,['小明', '小剛']才是真正的對象。通過p1.friends修改了這個數組,因為共享的問題,p2.friends訪問的也是同一個數組。假如我們的初衷就是共享一個數組,那麼也沒問題。但是多數情況下應該是不想共享的場景。比如這裡,張三新交了一個女朋友小紅,結果小紅同時也是李四的女朋友,是張三有這癖好?是小紅劈腿?還是人家張三隻是單純地交了個女朋友,被你搞得複雜了?這個說不清,既然說不清,那麼程序就有問題。所以很少有人單獨使用原型模式,那麼這個問題怎麼解決呢?辦法還是有的,那就是組合使用構造函數模式和原型模式,這個實現也很簡單,但為了區分原型模式,後面將會單獨列一篇文章。

想學習更多java知識的朋友可以進群:874811168 一起學習 還有全套的免費資料領取

本文參考《JavaScript高級程序設計(第3版)》,關於原型模式的其他特點讀者可以查閱第6.2.3章節,裡面有詳細的說明。

後臺私信回覆“Java”即可免費獲取資料一份 一起學習 一起進步


分享到:


相關文章: