摘要:雖然是弱類型的語言,但是也有構造函數和實例。也就是說,我們只在第一次調用構造函數時創建新對象,之后調用返回時返回該對象即可。而我不認為這是一個單例模式的原因如下我覺得既然兩次調用同一個構造函數,返回的不是同一個對象,那不就不能成為單例模式。
寫在前面
(度過一陣的繁忙期,又可以愉快的開始學習新知識了,一年來技術棧切來切去,卻總覺得js都還沒學完-_-)
本文主要圍繞js的設計模式進行展開,對每個設計模式從特征,原理和實現方式幾個方面進行說明。由于內容較長,所以拆分成多篇文章。如果有不對的地方歡迎指出,閱讀前請注意幾點:
如果對js的類式繼承和閉包不太熟練的建議先閱讀相關內容,比如我前面寫過的js繼承(主要看到原型鏈繼承部分就好)和js閉包,,
知識密度較大,建議邊思考,順便跑以下相關的代碼(如果碰到代碼有問題的歡迎指出),中途注意休息
正文 定義也叫單體模式,核心思想是確保一個類只對應一個實例。
雖然js是弱類型的語言,但是js也有構造函數和實例。所以這里可以理解為確保多次構造函數時,都返回同一個實例
根據定義,我們需要實現一個構造函數,并且滿足以下條件:
function A(){ //需要實現的函數內容 } var a1 = new A() var b1 = new A() a1 ==== b1 //true
在前面我們說到了構造函數和實例,并且也知道了引用類型的值賦值的時候存放的實際是變量的地址指針,所以要實現這個構造函數的核心思路是:每次調用構造函數時,返回指向同一個對象的指針。 也就是說,我們只在第一次調用構造函數時創建新對象,之后調用返回時返回該對象即可。所以重點變成了--如何緩存初次創建的變量對象。
首先先排除全局變量,因為一般情況下需要保證全局環境的純凈,其次全局變量容易被改寫,出現意外情況。所以采用以下2種方案來實現緩存。
1. 使用構造函數的靜態屬性因為構造函數本身也是對象,可以擁有靜態屬性。所以可以這樣實現:
function A(name){ // 如果已存在對應的實例 if(typeof A.instance === "object"){ return A.instance } //否則正常創建實例 this.name = name // 緩存 A.instance =this return this } var a1 = new A() var a2= new A() console.log(a1 === a2)//true
這種方法的缺點在于靜態屬性是能夠被人為重寫的,不過不會像全局變量那樣被無意修改。
2. 借助閉包通過閉包的方式來實現的核心思路是,當對象第一次被創建以后,重寫構造函數,在重寫后的構造函數里面訪問私有變量。
function A(name){ var instance = this this.name = name //重寫構造函數 A = function (){ return instance } } var a1 = new A() var a2= new A() console.log(a1 === a2)//true
到這里我們其實已經實現了最核心的步驟,但是這樣的實現存在問題,如果看過原型鏈繼承的小伙伴會注意到,如果我們在第一次調用構造函數之后,由于構造函數被重寫,那么在之后添加屬性和方法到A的原型上,就會丟失。比如:
function A(name){ var instance = this this.name = name //重寫構造函數 A = function (){ return instance } } A.prototype.pro1 = "from protptype1" var a1 = new A() A.prototype.pro2 = "from protptype2" var a2= new A() console.log(a1.pro1)//from protptype1 console.log(a1.pro2)//underfined console.log(a2.pro1)//from protptype1 console.log(a2.pro2)//underfined
重寫構造函數之后,,實際上原先的A指針對應的函數實際上還在內存中(因為instance變量還在被引用著,這里的內容如果忘記了請看閉包),但是此時A指針已經指向了一個新的函數了,可以簡單測試下:
console.log(a1.constructor ==== A)//false
所以接下來我們應該解決這個問題,根據上文可知,我們的重點是,調整原型實例之間的關系,所以應該這樣實現(這一塊忘記的還是建議回頭看看js繼承里面的那張函數、原型、實例之間的關系圖點擊直達):
function A(name){ var instance = this this.name = name //重寫構造函數 A = function (){ return instance } // 第一種寫法,這里實際上實現了一次原型鏈繼承,如果不想這樣實現,也可以直接指向原來的原型 A.prototype = this // 第二種寫法,直接指向舊的原型 A.prototype = this.constructor.prototype instance = new A() // 調整構造函數指針,這里實際上實現了一次原型鏈繼承,如果不想這樣實現,也可以直接指向原來的原型 instance.constructor = A return instance } A.prototype.pro1 = "from protptype1" var a1 = new A() A.prototype.pro2 = "from protptype2" var a2= new A() console.log(a1.pro1)//from protptype1 console.log(a1.pro2)//from protptype2 console.log(a2.pro1)//from protptype1 console.log(a2.pro2)//from protptype2
現在一切就正常了。還有一種方式,是利用立即執行函數來保持私有變量,(立即執行函數的內容請看《詳解js中的函數部分》)原理也是閉包:
var A; (function(name){ var instance; A = function(name){ if(instance){ return instance } //賦值給私有變量 instance = this //自身屬性 this.name = name } }()); A.prototype.pro1 = "from protptype1" var a1 = new A("a1") A.prototype.pro2 = "from protptype2" var a2 = new A("a2") console.log(a1.name) console.log(a1.pro1)//from protptype1 console.log(a1.pro2)//from protptype2 console.log(a2.pro1)//from protptype1 console.log(a2.pro2)//from protptype2
簡單說明一下上面的內容,首先利用在立即執行函數中保存一個私有變量instance,初次執行之后,第一次調用new A()之后,生成一個對象并讓instance指向該對象,從第二次開始,調用new A(),都只返回這個對象,
*特殊情況很多地方會提到,使用字面量直接創建一個對象也是一個單例模式的實例。這個說法我個人覺得并不夠嚴格,和同事探討之后覺得可能是這樣(如果有有其他見解的小伙伴歡迎指出):使用字面量寫法的時候,實際上相當于使用原生的Object函數new了一個對象,然后存儲到內存里,之后我們每次使用對應的指針去讀取時,讀到的都是這個對象。而我不認為這是一個單例模式的原因如下:
var obj1 = new Object({ name:111 }) var obj2 = new Object({ name:111 }) console.log(obj1===obj2)//false
我覺得既然兩次調用同一個構造函數,返回的不是同一個對象,那不就不能成為單例模式。當然,這一部分是我個人的看法,讀者朋友還是要注意區分。
小結單例模式先說到這里,后面會陸續補充其他的設計模式。
感謝之前的熱心讀者,尤其是為我指出錯誤的小伙伴。
然后依然是每次都一樣的結尾,如果內容有錯誤的地方歡迎指出;如果對你有幫助,歡迎點贊和收藏,轉載請征得同意后著明出處,如果有問題也歡迎私信交流,主頁添加了郵箱地址~溜了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95699.html
摘要:什么是設計模式設計模式是一種能夠被反復使用,符合面向對象特性的代碼設計經驗的總結,合理的使用設計模式能夠讓你得代碼更容易維護和可靠設計模式的類型共分為創建型模式,結構型模式,行為型模式三種創建型模式創建型模式是對一個類的實例化過程進行了抽象 什么是設計模式 設計模式是一種能夠被反復使用,符合面向對象特性的代碼設計經驗的總結,合理的使用設計模式能夠讓你得代碼更容易維護和可靠設計模式的類型...
摘要:什么是單例模式單例模式是一種十分常用但卻相對而言比較簡單的單例模式。對象就是單例模式的體現。總結單例模式雖然簡單,但是在項目中的應用場景卻是相當多的,單例模式的核心是確保只有一個實例,并提供全局訪問。 1. 什么是單例模式? 單例模式是一種十分常用但卻相對而言比較簡單的單例模式。它是指在一個類只能有一個實例,即使多次實例化該類,也只返回第一次實例化后的實例對象。單例模式不僅能減少不必要...
摘要:單例模式是一個用來劃分命名空間并將一批屬性和方法組織在一起的對象,如果它可以被實例化,那么它只能被實例化一次。 單例模式是一個用來劃分命名空間并將一批屬性和方法組織在一起的對象,如果它可以被實例化,那么它只能被實例化一次。 原文鏈接 單例模式優點 劃分命名空間,減少全局變量 組織代碼為一體,便于閱讀維護 并非所有的對象字面量都是單例,比如模擬數據 基本結構: let Cat = {...
摘要:以上,吐槽完畢設計模式主要分為三大類創建型模式結構型模式行為模式。單例模式所謂單例模式,是指僅實例化該類一次,該實例提供一個眾所周知的全局訪問點。單例模式暫時這么些,如果后續了解更多會默默補充上來,下一次會分享工廠模式。 初入js坑時,滿臉懵逼的我認為設計模式就該是后端頭疼的,對,頭疼,蓋因粗略掃描下來也就十幾二十種吧,彼時頗有種隔岸觀火看到你過得不好我也就安心的自得。染鵝,打臉啪啪的...
閱讀 1817·2021-11-18 13:21
閱讀 1953·2021-10-18 13:30
閱讀 1539·2021-10-12 10:13
閱讀 906·2021-10-09 09:43
閱讀 5413·2021-09-22 15:13
閱讀 3583·2021-08-11 10:22
閱讀 936·2019-08-30 13:46
閱讀 3520·2019-08-30 13:21