在本身研究javascript各類設計模式的過程當中,偶然寫出的一段代碼讓本身理解的更深入了,之因此稱之爲僞單例模式,是由於這段代碼形成的結果很想單例模式,可是其實是活動對象搗亂所形成的誤會。javascript
代碼很簡單是這樣的:html
function Person(){ var money = 0; Person.prototype.getMoney = function (){ return money; } Person.prototype.addMoney = function (m){ money += m; } } var a = new Person(); var b = new Person(); a.addMoney(20); console.log(a.getMoney());//打印20 console.log(b.getMoney());//打印20
這裏有些同窗可能會感受很奇怪了,a和b徹底是兩個不一樣的對象,每次new的時候都會把私有變量money初始化成0,爲何a對象使用addMoney()方法後,同時b對象的money也變成20了呢?java
這個時候會形成一種假象,就是經過new實例化多個對象的結果都是產生了同一個對象,彷彿就像單例模式那樣。設計模式
若是你對這個結果感到疑惑就接着看下吧,若是你一眼就看到其中的緣由,那你就不用在這裏浪費時間咯~閉包
咱們從這個構造函數提及,這裏我我使用了var來創造一個私有變量money,並在這個構造函數中提供了兩個匿名函數給構造函數的原型對象的getMoney和addMoney,即經過閉包的方式來提供對money變量的訪問權限,若是你把原型對象的寫在外面是訪問不到money這個私有變量的。函數
事實上偏偏由於我這個行爲致使了僞單例的發生,咱們接下來用圖來剖析一下當咱們new對象的時候,函數的活動對象發生了怎樣的變化。this
若是對函數的活動對象、執行環境不太理解,給個傳送門http://www.docin.com/p-509501990.html,講解的十分清楚。spa
當咱們var a = new Person()後,狀況是這樣的:prototype
實例對象a經過原型鏈能夠調用原型對象中的兩個屬性指向那兩個匿名函數(迷之圓圈),他們在閉包的幫助下訪問活動對象一的money屬性。此時money屬性初始化爲0。設計
當咱們var b = new Person()後,狀況變成了這樣:
如今能夠很清楚的看到,真正改變的是原型對象中屬性所指向的匿名函數,也就是說如今實例a和實例b經過原型中的訪問所訪問的money變量都是位於活動對象2中的,活動對象1已經被玩壞後拋棄了。
再看下一句的a.addMoney(20)實際上就是將活動對象2中的money變成了20,這就很明白了,最後他倆getMoney訪問到的都是活動對象2裏面的money,天然都會返回20了。則就形成了僞單例的效果。
總結要注意的幾點:
1,要達成僞單例的效果,必須將構造函數中的變量設爲私有變量而不是經過this設置爲實力屬性,由於那樣訪問的就不是經過閉包了。
2,給原型對象添加在構造函數內部才能訪問私有變量,不明白?還不去好好看閉包!
3,最後全部的對象訪問的都是最後new時,構造函數所造成的活動對象,對此有疑問的同窗能夠交換一下代碼執行的順序,好比改爲這樣:
var a = new Person(); a.addMoney(20);//寫在前面 var b = new Person(); console.log(a.getMoney());//返回0 console.log(b.getMoney());//返回0
這是很天然的,由於被你你添加的20的那個money在活動對象一中,當你創造活動對象2時,實例對象a已經移情別戀了,a和b如今都指向活動對象2了,其中money被初始化成0,不懂得同窗多看看圖喲。