JavaScript設計模式基礎之閉包(終)

来源:https://www.cnblogs.com/y-y-y-y/archive/2018/09/24/9695498.html
-Advertisement-
Play Games

對於前端程式員來說閉包還是比較難以理解的, 閉包的形成與變數的作用域以及變數的生產周期密切相關,所以要先弄懂變數的作用域和生存周期。 1.變數作用域 變數的作用域,就是指變數的有效範圍,通常我們指的作用域就是函數作用域(畢竟全局的作用域沒有要指的意義,關鍵哪都能訪問) 聲明變數的時候推薦使用es6語 ...


對於前端程式員來說閉包還是比較難以理解的,

閉包的形成與變數的作用域以及變數的生產周期密切相關,所以要先弄懂變數的作用域和生存周期。

1.變數作用域

  變數的作用域,就是指變數的有效範圍,通常我們指的作用域就是函數作用域(畢竟全局的作用域沒有要指的意義,關鍵哪都能訪問)

  聲明變數的時候推薦使用es6語法中的let 和const 可以避免var聲明變數出現的一些不必要的錯誤而且let聲明變數只作用於當前作用域 避免使用不帶var 或者let直接聲明變數,可能會導致命名衝突。

2.變數生存周期

  除了變數作用域之外,另外一個跟閉包有關的概念就是變數生存周期。

  對於全局變數來說,它的生存周期就是永久,除非我們主動銷毀它,而對於函數裡面聲明的變數來說 它的生存周期會隨著函數調用解釋而被銷毀。

閉包的定義: 最簡單直白的說法就是 函數返回函數

閉包的應用:封裝私有變數、延續局部變數的壽命

1.封裝私有變數:

  使用閉包可以把一些不需要暴露在全局的變數封裝成“私有變數”

  如有一個計算數組偶數乘積的方法:

    let num = function(arr){
        let a = 1;
        for(let i = 0; i < arr.length; i++){
            if(arr[i] % 2 === 0){
                a *= arr[i];
            }
        }
        return a;
    }
   
    console.log( num([1,2,3,4]));//輸出8

加入緩存機制提高函數性能:

let cache = {};
    let num = function(arr){
        let args = Array.prototype.join.call(arr,',');//輸出1,2,3,4
        console.log(cache[args])//第一次調用輸出為undefined進行下一步計算 第二次調用輸出8 直接返回
        //傳入相同參數就比不必進行計算 直接返回緩存提高性能
        if(cache[args]){
            return cache[args];
        }
        //不是相同參數則進行計算
        let a = 1;
        for(let i = 0; i < arr.length; i++){
            if(arr[i] % 2 === 0){
                a *= arr[i];
            }
        }
        return cache[args] = a;
    }
   
    console.log( num([1,2,3,4]));//8 進行計算
    console.log( num([1,2,3,4]));//8 返回緩存

這明顯能看到cache這個緩存變數只在num函數裡面被使用,與其讓它們一起暴露在全局不然把它封裝在num函數內部,減少頁面中的全局變數,以免該變數在其他地方被修改而引發錯誤

封裝後代碼如下:

  

let num = (function(){
        let cache = {};
        return function(arr){
            let args = Array.prototype.join.call(arr,',');//輸出1,2,3,4
            console.log(cache[args])//第一次調用輸出為undefined進行下一步計算 第二次調用輸出8 直接返回
            //傳入相同參數就比不必進行計算 直接返回緩存提高性能
            //判斷cache緩存對象裡面有args這個key值沒
            if(args in cache){
                return cache[args];
            }
            //不是相同參數則進行計算
            let a = 1;
            for(let i = 0; i < arr.length; i++){
                if(arr[i] % 2 === 0){
                    a *= arr[i];
                }
            }
            return cache[args] = a;
        }
       
    })();
   
    console.log( num([1,2,3,4]));//8 進行計算
    console.log( num([1,2,3,4]));//8 返回緩存

2.延續局部變數壽命

src屬性會自動請求伺服器數據如下

  let report = function(src){
            let img = new Image();
            img.src = src;
            console.log(img.src);
        }
        report(`https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537779456907&di=c72dd79d1dbb02bb9340743bf08e99f7&imgtype=0&src=http%3A%2F%2Fe.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F94cad1c8a786c91723e93522c43d70cf3ac757c6.jpg`);

 

  但是一些低版本的瀏覽器實現存在著bug,在這些瀏覽器上面使用該函數會丟失數據 因為函數調用結束後變數銷毀 我們可以用閉包封閉起來就能解決低版本瀏覽器bug

代碼如下:

  let report = (function(){
            let imgs = [];
            return function(src){
                let img = new Image();
                imgs.push(img);
                img.src = src;
            }
            
        })()
        report(`https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537779456907&di=c72dd79d1dbb02bb9340743bf08e99f7&imgtype=0&src=http%3A%2F%2Fe.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F94cad1c8a786c91723e93522c43d70cf3ac757c6.jpg`);

 

接下來要來點乾貨了 

用閉包實現命令模式:

在JavaScript中閉包的各種設計模式實現裡面,閉包的運用特別廣泛,在我後續的博客中將體會到這一點

簡單編寫一段閉包實現命令模式 如果上述的閉包使用你基本會了的話不會對我們的理解造成困難

代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <button id="start">打開電腦</button>
    <button id="end">關閉電腦</button>
    <script>
        //命令
        let Computer = {
            open(){
                alert('打開電腦');
            },
            close(){
                alert('關閉電腦');
            }
        }
        //創建命令執行中介
        let createCommand = function(receiver){
            //執行
            let execute = function(){
                return receiver.open();
            }
            //關閉
            let undo = function(){
                return receiver.close();
            }
            return {
                execute,
                undo
            }
        };
        //設置執行命令者
        let setCommand = function(command){
            document.querySelector('#start').onclick = function(){
                command.execute();//輸出打開電腦
            }
            document.querySelector('#end').onclick = function(){
                command.undo();//輸出關閉電腦
            }
        }
        //傳入命令方法 傳入執行中介 
    setCommand(createCommand(Computer));
    </script>
</body>
</html>

代碼還是不難重在理解 

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 旭日Follow_24 的CSDN 博客 ,全文地址請點擊: https://blog.csdn.net/xuri24/article/details/80963801 慢查詢日誌概念 MySQL的慢查詢日誌是MySQL提供的一種日誌記錄,它用來記錄在MySQL中響應時間超過閥值的語句,具體指運行時 ...
  • 旭日Follow_24 的CSDN 博客 ,全文地址請點擊: https://mp.csdn.net/postedit/80910082 索引概念: 索引是關係資料庫中用於存放每一條記錄的一種對象,主要目的是加快數據的讀取速度和完整性檢查。建立索引是一項技術性要求高的工作。一般在資料庫設計階段的與數 ...
  • Android中的構架模式一直是一個很hot的topic, 近年來Architecture components推出之後, MVVM異軍突起, 風頭正在逐漸蓋過之前的MVP. 其實我覺得MVP還是有好處的, 比如靈活多變(其實只是我用起來更熟悉順手一些吧). 個人是沒有什麼偏見的, 關於項目的構架,... ...
  • 線性佈局線性佈局LinearLayout是最常用的佈局,顧名思義,它下麵的子視圖像是用一根線串了起來,所以其內部視圖的排列是有順序的,要麼從上到下垂直排列,要麼從左到右水平排列。排列順序只能指定一維方向的視圖次序,可是手機屏幕是個二維的平面,這意味著還剩另一維方向需要指定視圖的對齊方式。故而線性佈局 ...
  • 開篇呢,先給大家問個好,今天是中秋節,祝大家中秋節快樂!!雖然是中秋節,但是木有回家還是總結一下知識點寫寫博客吧,想著昨天總結一下的,但是昨天和幾個同學小聚了一下,酒逢知己總是千杯少呢,喝的微醺不適合寫東西,所以就留到今天總結了。因為這段時間在工作中陸陸續續的接觸到了一些RN開發的東西,還是需要總結 ...
  • Cookie和Session在Node.JS中的實踐(二) cookie篇在作者的上一篇文章 "Cookie和Session在Node.JS中的實踐(一)" 已經是寫得算是比較詳細了,有興趣可以翻看,這篇是session篇,重點在討論seesion的特性、概念,以及session和cookie的區別 ...
  • Cookie和Session在Node.JS中的實踐(一) Cookie和Session是一個非常有趣的概念,也是一個老生常談的話題。然而,作者看了許多文章,也翻看了幾本書籍,它們對Cookie和Session的概念、機制的描述都各不一致,大多文章都只談到了Cookie和Session其中之一,但在 ...
  • React作為受歡迎的前端框架之一,大多數人只會用而不理解其原理,本系列屬於筆記,來源於深入React技術棧,並會適時加入補充內容,以便讀者能理解React底層實現,包括virtual DOM機制、生命周期等。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...