欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript設(shè)計(jì)模式之單例模式應(yīng)用場(chǎng)景案例詳解

 更新時(shí)間:2023年05月29日 11:07:33   作者:一顆冰淇淋  
這篇文章主要為大家介紹了JavaScript中單例模式的應(yīng)用場(chǎng)景案例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

單例模式

如果希望自己的代碼更優(yōu)雅、可維護(hù)性更高以及更簡(jiǎn)潔,往往離不開(kāi)設(shè)計(jì)模式這一解決方案。

在JS設(shè)計(jì)模式中,最核心的思想:封裝變化(將變與不變分離,確保變化的部分靈活,不變的部分穩(wěn)定)。

那么來(lái)說(shuō)說(shuō)第一個(gè)常見(jiàn)的設(shè)計(jì)模式:單例模式。

單例模式保證一個(gè)類(lèi)僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)方式,為了解決一個(gè)全局使用的類(lèi)頻繁被創(chuàng)建和銷(xiāo)毀、占用內(nèi)存的問(wèn)題。

ES5中通過(guò)閉包

在ES5中,可以使用閉包(函數(shù)內(nèi)部返回函數(shù)被外界變量所引用,導(dǎo)致這個(gè)函數(shù)里面的變量無(wú)法被釋放,就構(gòu)建成閉包)來(lái)保存這個(gè)類(lèi)的實(shí)例。

var Singeton = (function(){
    var instance;
    function User(name,age){
        this.name=name;
        this.age=age;
    }
    return function(name,age){
        if(!instance){
            instance = new User(name,age)
        }
        return instance
    }
})()

此時(shí)這個(gè)實(shí)例一旦生成,每次都是返回這個(gè)實(shí)例,且不會(huì)被修改,可以看到下面的代碼,當(dāng)給 User 對(duì)象初始賦值 name:alice,age:18 時(shí),以后再賦值便無(wú)效了,以及每次返回都是初始的實(shí)例對(duì)象。

ES6中使用類(lèi)的靜態(tài)屬性

以上代碼使用ES6語(yǔ)法來(lái)實(shí)現(xiàn),通過(guò)類(lèi)的靜態(tài)屬性來(lái)保存唯一的實(shí)例對(duì)象。

class Singeton {
    constructor(name,age){
        if(!Singeton.instance){
            this.name = name;
            this.age = age;
            Singeton.instance = this;
        }
       return Singeton.instance;
    }
}

創(chuàng)建方式仍然是一樣的,通過(guò) new 關(guān)鍵字創(chuàng)建類(lèi)的實(shí)例對(duì)象。

案例

那這樣一種設(shè)計(jì)模式在開(kāi)發(fā)中實(shí)際有什么用途呢?我們?cè)囅脒@樣一個(gè)業(yè)務(wù)場(chǎng)景:訪問(wèn)網(wǎng)站時(shí),很久沒(méi)有操作頁(yè)面,此時(shí)授權(quán)過(guò)期,當(dāng)我們點(diǎn)擊頁(yè)面上的任何一個(gè)地方,都會(huì)彈出一個(gè)登錄框。

那么這個(gè)登錄框,是全局唯一的,不會(huì)存在多份,也不會(huì)互相沖突,所以不需要每次都創(chuàng)建一份,保留初始那一份就夠了。

提前創(chuàng)建節(jié)點(diǎn)

我們可能會(huì)想到首先在頁(yè)面中提前創(chuàng)建節(jié)點(diǎn),編寫(xiě)好頁(yè)面樣式,最后通過(guò)控制元素的 display 屬性來(lái)達(dá)到顯示和隱藏的效果。

<div class="modal">登錄對(duì)話框</div>
<button id="open">打開(kāi)</button>
<button id="close">關(guān)閉</button>
<style>
  .modal {
    display: none;
    /* 其他布局代碼省略 */
  }
</style>
<script>
  document.querySelector("#open").onclick = function(){
     const modal = document.querySelector('.modal')
     modal.style.display = 'block'
  }
</script>

這樣可以完成需求,全局只有一個(gè)登錄框,每次都展示同一個(gè)。但問(wèn)題是dom元素從一開(kāi)始它創(chuàng)建好并添加到body中,無(wú)論是否需要用到,如果有些場(chǎng)景不需要登陸,那么這里初始渲染就會(huì)浪費(fèi)空間。

單例模式

那如果不需要初始渲染,僅當(dāng)需要時(shí)才使用,并且每次都返回同一個(gè)實(shí)例的單例模式應(yīng)該如何實(shí)現(xiàn)呢?

我們可以這樣處理

<!-- 去除class為modal的標(biāo)簽,動(dòng)態(tài)創(chuàng)建 -->
<script>
const Modal = (function(){
  let instance = null
  return function(){
      if(!instance){
          instance = document.createElement("div")
          instance.innerHTML = "登錄對(duì)話框"
          instance.className = "modal"
          instance.style.display = "none"
          document.body.appendChild(instance)
      }
      return instance
  }
})()
document.querySelector("#open").onclick = function(){
      //創(chuàng)建modal,如果放在外面,一開(kāi)始就會(huì)創(chuàng)建元素
      const modal = Modal()    
      //顯示modal
      modal.style.display = "block"
  }
  document.querySelector("#close").onclick = function(){
      const modal = Modal()    
      modal.style.display = "none"
  }
</script>

雖然上面的方式可以達(dá)到效果,但是創(chuàng)建對(duì)象和管理單例的邏輯都放在了對(duì)象內(nèi)部,是有些混亂的。并且如果下次需要?jiǎng)?chuàng)建頁(yè)面中唯一的 iframe,或者 script 標(biāo)簽,就得將以上函數(shù)照抄一遍。

通用單例

首先拆分函數(shù)邏輯,將執(zhí)行創(chuàng)建對(duì)象的邏輯拿出來(lái)

const createLayer = function(){
  let div = document.createElement("div")
  div.innerHTML = "登錄對(duì)話框"
  div.className = "modal"
  div.style.display = "none"
  document.body.appendChild(div);
  return div;
}
const Modal = (function(){
  let instance = null
  return function(){
      if(!instance){
          instance = createLayer()
      }
      return instance
  }
})()

以上修改后代碼邏輯就更為清晰,但此時(shí)還不支持通用化的創(chuàng)建別的組件,這時(shí)候我們想想如何將創(chuàng)建單例的方法進(jìn)行一些優(yōu)化,是否可以將單例需要執(zhí)行的函數(shù)抽象化。

const createSingle = (function(fn){
    let instance; 
    return function(){
        return instance || ( instance = fn.apply(this, arguments))
    }
})()

這樣改造后,如果存在創(chuàng)建 iframe 的方法,也可以直接使用。

const createIframe = function() {
  const iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  document.body.appendChild(iframe);
  return iframe
}
const singleIframe = createSingle(createIframe)
document.querySelector("#open").onclick = function(){
 const iframe = singleIframe()
 iframe.style.display = 'block'
}

實(shí)際應(yīng)用

以上都是咱小打小鬧的試用,那再來(lái)看看社區(qū)中一些非常棒的實(shí)現(xiàn)吧~ 比如:React 中常用的狀態(tài)管理工具 Redux 就使用到了單例模式,它有這樣一些要求。

  • 單一數(shù)據(jù)源:整個(gè)應(yīng)用的 state 只存在于唯一一個(gè) store 中。
  • State 是只讀的:不要直接改變 state 的值,唯一改變 state 的方法就是觸發(fā) action。
  • reducer 是純函數(shù):需要編寫(xiě)純函數(shù) reducer 來(lái)修改 state 的值。

來(lái)看看 Redux 的源碼,為了便于閱讀已刪減部分邏輯判斷和注釋?zhuān)梢钥吹酵ㄟ^(guò) store 的 getState 方法每次獲取閉包中的 currentState。

單例模式在內(nèi)存中只有一個(gè)實(shí)例,可以減少內(nèi)存開(kāi)支,同時(shí)還能在系統(tǒng)設(shè)置全局的訪問(wèn)點(diǎn),優(yōu)化和共享資源。

以上就是單例模式的相關(guān)介紹。更多有關(guān) 前端、設(shè)計(jì)模式 的內(nèi)容請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序 視圖層(xx.xml)和邏輯層(xx.js)詳細(xì)介紹

    微信小程序 視圖層(xx.xml)和邏輯層(xx.js)詳細(xì)介紹

    這篇文章主要介紹了微信小程序 視圖層(xx.xml)和邏輯層(xx.js)詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • 微信小程序 Toast自定義實(shí)例詳解

    微信小程序 Toast自定義實(shí)例詳解

    這篇文章主要介紹了微信小程序 Toast自定義實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Web?Animations?API實(shí)現(xiàn)一個(gè)精確計(jì)時(shí)的時(shí)鐘示例

    Web?Animations?API實(shí)現(xiàn)一個(gè)精確計(jì)時(shí)的時(shí)鐘示例

    這篇文章主要為大家介紹了Web?Animations?API實(shí)現(xiàn)一個(gè)精確計(jì)時(shí)的時(shí)鐘示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • JavaScript 中的文檔對(duì)象模型 DOM

    JavaScript 中的文檔對(duì)象模型 DOM

    DOM,即文檔對(duì)象模型,前端開(kāi)發(fā)工程師必學(xué)的基礎(chǔ)知識(shí),在本文將介紹如何在 HTML 文檔中選擇元素、如何創(chuàng)建元素、如何更改內(nèi)聯(lián) CSS 樣式以及如何監(jiān)聽(tīng)事件,需要的朋友可以參考一下
    2021-10-10
  • Thinkphp5微信小程序獲取用戶(hù)信息接口的實(shí)例詳解

    Thinkphp5微信小程序獲取用戶(hù)信息接口的實(shí)例詳解

    這篇文章主要介紹了Thinkphp5微信小程序獲取用戶(hù)信息接口的實(shí)例詳解的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • 微信小程序 Storage API實(shí)例詳解

    微信小程序 Storage API實(shí)例詳解

    這篇文章主要介紹了微信小程序 Storage API實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • 微信小程序 歡迎頁(yè)面的制作(源碼下載)

    微信小程序 歡迎頁(yè)面的制作(源碼下載)

    這篇文章主要介紹了微信小程序 歡迎頁(yè)面的制作含(源碼下載)的相關(guān)資料,這里實(shí)現(xiàn)歡迎頁(yè)面,開(kāi)始做應(yīng)用的時(shí)候都會(huì)用到,需要的朋友可以參考下
    2017-01-01
  • Google 地圖獲取API Key詳細(xì)教程

    Google 地圖獲取API Key詳細(xì)教程

    本文主要介紹Google 地圖API Key,開(kāi)發(fā)Google 地圖應(yīng)用的朋友都知道,在開(kāi)發(fā)的前需要免費(fèi)的Google 地圖API Key,這里詳細(xì)給出獲得API Key的流程,有需要的小伙伴參考下
    2016-08-08
  • JavaScript事件委托原理

    JavaScript事件委托原理

    這篇文章主要介紹了JavaScript事件委托原理,?事件委托也稱(chēng)為事件代理。就是利用事件冒泡,把子元素的事件都綁定到父元素上。如果子元素阻止了事件冒泡,那么委托就無(wú)法實(shí)現(xiàn),下面我們一起來(lái)學(xué)習(xí)文章的具體詳細(xì)內(nèi)容吧
    2021-12-12
  • Promise改寫(xiě)獲取螢石云直播地址接口示例

    Promise改寫(xiě)獲取螢石云直播地址接口示例

    這篇文章主要為大家介紹了Promise改寫(xiě)獲取螢石云直播地址接口示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評(píng)論