初識js中的閉包

来源:http://www.cnblogs.com/pssp/archive/2016/02/19/5189345.html
-Advertisement-
Play Games

今天看了關於js閉包方面的文章,還是有些雲里霧裡,對於一個菜鳥來說,學習閉包確實有一定的難度,不說別的,能夠在網上找到一篇優秀的是那樣的不易。 當然之所以閉包難理解,個人覺得是基礎知識掌握的不牢,因為閉包牽扯到一些前面的東西,比如作用域\等等,如果連基本的作用域都沒有弄清楚,自然不可能搞懂閉包,還有


  今天看了關於js閉包方面的文章,還是有些雲里霧裡,對於一個菜鳥來說,學習閉包確實有一定的難度,不說別的,能夠在網上找到一篇優秀的是那樣的不易。

  當然之所以閉包難理解,個人覺得是基礎知識掌握的不牢,因為閉包牽扯到一些前面的東西,比如作用域\等等,如果連基本的作用域都沒有弄清楚,自然不可能搞懂閉包,還有就是對js的實踐比較少,因為你根本就不知道什麼時候要用這東西,自然談不上對閉包的深刻理解。

  今天我就簡單的說說我目前所理解的閉包,當然可能不完全正確,但是我相信會給你一定的啟發。

 

  首先我們來談談js中的變數,如果你不知道我為什麼要說這些,那麼你根本沒有掌握js的基礎,建議回頭複習。

js中分:全局變數 和 局部變數

  全局變數:可以在任意位置訪問的量就叫全局變數

    

1 var age = 20;
2 function a(){
3     console.log(age); >>20
4 }
5 a();

  局部變數:函數中用var定義的變數,只能在函數中訪問這個變數,函數外部訪問不了。

1 function a(){
2     var age = 20;
3 }
4 a();
5 console.log(age); >> Uncaught ReferenceError: age is not defined

 

註意點1:在函數中如果不使用var定義變數那麼js引擎會自動添加成全局變數。

註意點2:全局變數從創建的那一刻起就會一直保存在記憶體中,除非你關閉這個頁面,局部變數當函數運行完以後就會銷毀這個變數,假如有多次調用這個函數它下一次調用的時候又會重新創建那個變數,既運行完就銷毀,回到最初的狀態,簡單來說局部變數是一次性的,用完就扔,下次要我再重新創建。

 

函數的相關知識點:

        1. 一個函數內可以嵌套多個函數

    2. 函數裡面的子函數可以訪問它上級定義的變數,註意不只是一級,如果上級沒有會繼續往上級找,直到找到為止,如果找到全局變數到找不到就會報錯。

     

1 function a(){
2     var name = "追夢子";
3     function b(){
4         console.log(name); >> "追夢子"
5     }
6     b();
7 }
8 a();

    3. 函數的另外一種調用形式,你可以把它叫做自調用,自己調用自己,達到自執行的效果。

   

1 var a = 0;
2 (function(){
3    console.log(++a); >>1
4 })()

這種方式用()把內容包裹起來,後面的()表示執行這個函數,可能你會問為什麼要把函數包起來,如果不包裹起來,js會把它當作函數聲明來處理,如果包裹起來就是表達式,還沒有看懂就上網查吧。

 

 

開始我們正式閉包部分---------------------------- 幣包 ---------------像錢包一樣的東西,可以把東西包裹起來----------

      首先我們來看看為什麼需要學習閉包,加以理解 -- 0 v  0- -

 

1 function a(){
2    var num = 0;
3    console.log(++num);
4 }
5 a(); >>1
6 a(); >>1

上面代碼輸出了兩次1,為什麼呢?如果你有看我上面的關於變數部分肯定能夠想到個大概。

  前面我們說過了函數執行完以後,裡面的變數(即局部變數)就會銷毀,下一次運行又會重新創建那個變數,所以雖然你第一次++num了但是這個變數在第一次執行完畢以後就被銷毀了。

那麼我們怎麼樣才能確保第一次的變數不被銷毀,那麼就需要我們的閉包出場了。

溫馨提示:JavaScript中有回收機制,函數沒有被引用執行完以後這個函數的作用域就會被銷毀,如果一個函數被其他變數引用,這個函數的作用域將不會被銷毀,(簡單來說就是函數裡面的變數會被保存下來,你可以理解成全局變數。)

…………………………………………………………………………………… 當 當 當 ................. 下麵有請我們的幣包同志

 

function a(){
    var aa = 0;
    function b(){
        aa ++;
        console.log(aa);
    }
    return b;
}
var ab = a();
ab(); //1
ab(); //2

看到了吧裡面的變數的值沒有被銷毀,因為函數a被外部的變數ab引用,所以變數aa沒有被回收。

     如果某個函數被它的父函數之外的一個變數引用,就形成了一個閉包

還有一種更為常用的閉包寫法

var bi = (function(){
    var a = 0;
    function b(){
        a ++;
        console.log(a);
    }
    return b;
})();

bi(); //1
bi(); //2
bi(); //3

執行過程分析:

  首先把一個自執行函數賦值給了bi,這個自執行函數運行完成以後就bi的值就變成了

function b(){
    a ++;
    console.log(a);
}

  因為我們在上面的代碼return回去了b,然後因為這個自執行函數被bi引用所以裡面的變數a並沒有因為這個自執行函數執完而銷毀,而是保存到了記憶體中,所以我們多次列印bi()就成了1、2、3

 

下麵我來說一個閉包的使用場景吧。

   沒有使用閉包的版本

window.onload = function(){
    var ul = document.getElementsByTagName("ul")[0];
    var li = ul.getElementsByTagName("li");
    for(var i=0;i<li.length;i++){
        li[i].onclick = function(){
            console.log(i); //不管我怎麼點都是返回6
        }
    }
}

  使用了閉包的版本

window.onload = function(){
    var ul = document.getElementsByTagName("ul")[0];
    var li = ul.getElementsByTagName("li");
    for(var i=0;i<li.length;i++){
        (function(i){
            li[i].onclick = function(){
                console.log(i); //點擊第幾個返回第幾個
            }
        })(i)
    }
}

、、、、、如果你不理解這個,你只要這樣子用就能夠達到效果。

 

這也只是簡單的介紹了一下,後面將會在閉包的高級部分講解。如果你對閉包有更深的理解可以pm我。


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

-Advertisement-
Play Games
更多相關文章
  • position:屬性規定元素的定位類型。 取值:static | absolute | fixed | relative static : 預設值。無特殊定位 。對象遵循HTML定位規則。 absolute(絕對定位) : 將對象從文檔流中拖出(可層疊)。用left, right, top, bo
  • [1]line-height [2]font-size [3]vertical-align
  • Web 項目或多或少都會有涉及到什麼人員職稱樹,菜單樹,組織機構樹...... 歷手三四個項目有大有小,採用的樹前端都是 Ztree。 有些優秀的J2EE 框架將這些常用的組件都封裝起來,作為模塊化的組件提供給前端,這樣固然是好,開發效率會提升幾倍。 客戶需求是什麼,組件化往上一套,幾分鐘就能搭建起
  • 比較深入全面地介紹了什麼是同源策略,同源策略的影響以及如何繞過同源策略進行CSRF攻擊。同時跨域請求的實際應用,通過案例分析跨域請求的幾種辦法:cors、jsonp、子域域父域、iframe跨父域、postMessage實現frame和父視窗的通信
  • Myeclipse 環境下Freemarker Editor
  • 在討論jquery對象和DOM對象的相互轉換之前,先約定好定義變數的風格如果獲取的是jquery對象,那麼在變數前面加上$,例如 var $varible = jquery對象; 如果獲取的是DOM對象,則定義如下: var varible = DOM對象; 1.jquery對象轉成DOM對象: j
  • 1.動態載入腳本 <script type="text/javascript"> function loadScript(url){ var script=document.createElement("script"); script.type="text/javascript"; script.
  • 代碼: 輸出結果 補充: reg.lastIndex:下一次正則捕獲的開始查找的索引位置 ->正則的懶惰性就是因為預設情況下lastIndex值都是0,我們不管執行幾次exec,都是從字元串的開始位置查找,那麼每一次捕獲到的都是第一個符合的內容
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...