單例模式 (Singleton) 的實如今於保證一個特定類只有一個實例,第二次使用同一個類建立新對象的時候,應該獲得與第一次建立對象徹底相同的對象。
當建立一個新對象時,實際上沒有其餘對象與其相似,由於新對象已是單例了 {a:1} === {a:1} // false
。html
可是如何在對構造函數使用 new 操做符建立多個對象的時候僅獲取一個單例對象呢。前端
在構造函數的靜態屬性中緩存該實例,缺點在於 instance 屬性是公開可訪問的屬性,在外部代碼中可能會修改該屬性。segmentfault
function Universe() { if (typeof Universe.instance === 'object') { // 判斷是否已經有單例了 return Universe.instance } Universe.instance = this return this } var uni1 = new Universe() var uni2 = new Universe() uni1 === uni2 // true
能夠把實例封裝在閉包中,這樣能夠保證該實例的私有性而且保證該實例不會在構造函數以外被修改,代價是帶來了額外的閉包開銷。設計模式
function Universe() { var instance = this Universe = function() { // 重寫構造函數 return instance } } var uni1 = new Universe() var uni2 = new Universe() uni1 === uni2 // true
當第一次調用構造函數時,它正常返回 this ,而後在之後調用時,它將會執行重寫構造函數,這個構造函數經過閉包訪問了私有 instance
變量,而且簡單的返回了該 instance
。緩存
有時候對於單例對象須要延遲建立,因此在單例中還存在一種延遲建立的形式,也有人稱之爲惰性建立
。微信
const LazySingle = (function() { let _instance // 單例的實例引用 function Single() { // 單例構造函數 const desc = '單例' // 私有屬性和方法 return { // 暴露出來的對象 publicMethod: function() {console.log(desc)}, publickProperty: '1.0' } } return function() { return _instance || (_instance = Single()) } })() console.log(LazySingle()===lazySingle()) // true console.log(LazySingle().publickProperty) // 1.0
以前在構造函數中重寫自身會丟失全部在初始定義和重定義之間添加到其中的屬性。在這種狀況下,任何添加到 Universe()
的原型中的對象都不會存在指向由原始實現所建立實例的活動連接:閉包
function Universe() { var instance = this Universe = function() { return instance } } Universe.prototype.nothing = true var uni1 = new Universe() Universe.prototype.enthing = true var uni2 = new Universe() console.log(uni1 === uni2) // true uni1.nothing // true uni2.nothing // true uni1.enthing // undefined uni2.enthing // undefined uni1.constructor.name // "Universe" uni1.constructor === Universe // false
之因此 uni1.constructor
再也不與 Universe()
相同,是由於uni1.constructor仍然指向原始的構造函數,而不是重定義以後的那個構造函數。
能夠經過一些調整實現原型和構造函數指針按照預期的那樣運行:函數
function Universe() { var instance Universe = function Universe() { return instance } Universe.prototype = this // 保留原型屬性 instance = new Universe() instance.constructor = Universe // 重置構造函數指針 instance.start_time = 0 // 一些屬性 instance.big = 'yeah' return instance } Universe.prototype.nothing = true var uni1 = new Universe() Universe.prototype.enthing = true var uni2 = new Universe() console.log(uni1 === uni2) // true uni1.nothing & uni2.nothing & uni1.enthing & uni2.enthing // true uni1.constructor.name // "Universe" uni1.constructor === Universe // true uni1.big // "yeah" uni2.big // "yeah"
本文是系列文章,能夠相互參考印證,共同進步~學習
網上的帖子大多深淺不一,甚至有些先後矛盾,在下的文章都是學習過程當中的總結,若是發現錯誤,歡迎留言指出~this
參考:
《JavaScript模式》 P143
《Javascript 設計模式》 - 張榮銘
設計模式之單例模式
PS:歡迎你們關注個人公衆號【前端下午茶】,一塊兒加油吧~
另外能夠加入「前端下午茶交流羣」微信羣,長按識別下面二維碼便可加我好友,備註加羣,我拉你入羣~