那些年我們一起過的JS閉包,作用域,this,讓我們一起划上完美的句號。

来源:http://www.cnblogs.com/pssp/archive/2016/08/17/5781090.html
-Advertisement-
Play Games

之前有寫過閉包,作用域,this方面的文章,但現在想想當時寫的真是廢話太多了,以至於繞來繞去的,讓新手反而更難理解了,所以就有了此篇文章,也好和閉包,作用域,this告一段落。 第一個問題:什麼是閉包? 我不想回答這個問題,但是我可以告訴你的是閉包可以解決函數外部無法訪問函數內部變數的問題。下麵是一 ...


  之前有寫過閉包,作用域,this方面的文章,但現在想想當時寫的真是廢話太多了,以至於繞來繞去的,讓新手反而更難理解了,所以就有了此篇文章,也好和閉包,作用域,this告一段落。

    

    第一個問題:什麼是閉包?

    我不想回答這個問題,但是我可以告訴你的是閉包可以解決函數外部無法訪問函數內部變數的問題。下麵是一段沒有使用閉包的代碼:

  function fn(){

    var a = 10;

  }

     alert(a);

     //報錯了,因為a沒有定義,雖然函數fn裡面定義了a但是,但是它只能在函數fn中使用。也就是作用域的問題。

   再看‘閉包可以解決函數外部無法訪問函數內部變數的問題’這段話,好像有點意思,那麼究竟閉包是怎麼做的,看下麵代碼。

  function fn(){

        //定義了一個變數name

   var name = '追夢子';

        //我現在想在外部訪問這個變數name怎麼辦呢?哈:不是有return,我把它返回出去,我再用個變數接收一下不就可以了,哈哈哈哈~~~~~

         return name;

      }

      var name = fn();//接收fn返回的name值。

      alert(name);//追夢子;

     ·······這裡的閉包就是利用函數的return。除了通過return還可以通過其他的幾種方法如下:

  

  方法1:

    

function fn(){
  var a = 0;
  b = a;
}
alert(b)

  這裡利用了js的一個特性,如果在函數中沒有用var定義變數,那麼這個變數屬於全局的,但這種方法多少有些不好。

  

  方法2:

  

var f = null;
function fn(){
  var a = 0;
  f = function(){
    a++;
    f.a = a;
  };
}
fn();
f();
alert(f.a);//1
f();
alert(f.a);//2

 

    但好像也沒有那樣神奇對吧?其實閉包還有一個很重要的特性。來看一個例子。

  var lis= document.getElementsByTagName['li']; 

  //假如這段代碼中的lis.length = 5;

      for(var i=0;i<lis.length;i++){

    lis[i].onclick = function(){

      alert(i);

    };

     }

  最終結果是不管單擊哪個li元素都是彈5。不信你試試。為什麼呢。看下麵分析。

    

  for(var i=0;i<lis.length;i++){

      }

      // i = 5對吧

  lis[0].onclick = function(){

    alert(i); 

  };

  lis[1].onclick = function(){

    alert(i); 

  };

  lis[2].onclick = function(){

    alert(i);

  };

  lis[3].onclick = function(){

    alert(i);

  };

  lis[4].onclick = function(){

    alert(i);

  };

    為什麼會這樣呢,因為你for迴圈只是給li綁定事件,但是裡面的函數代碼並不會執行啊,這個執行是在你點擊的時候才執行的好吧?但是此時的i已經是5了,所以所有的都列印出5來了。

  如果想解決這個問題我們可以使用閉包,閉包的特點不只是讓函數外部訪問函數內部變數這麼簡單,還有一個大的特點就是通過閉包我們可以讓函數中的變數持久保持。來看。

  function fn(){

    var num = 0;

   return function(){

    num+=1;

           alert(num);   

         };  

      }

      var f = fn();

      f(); //1

      f(); //2

     如果你是初學者可能沒覺得這有什麼。OK,讓你看個東西。

  function fn(){

        var num = 5;

        num+=1;

        alert(num);

     }  

    fn(); //6

    fn(); //6

     為什麼呢?因為函數一旦調用裡面的內容就會被銷毀,下一次調用又是一個新的函數,和上一個調用的不相關了,不過有個特殊的情況,看這:

  

  function fn(){

    var num = 0;

   return function(){

    num+=1;

           alert(num);   

         };  

      }

      var f = fn();

      f(); //1

      f(); //2

    

    這段代碼很簡單,不要被它欺騙了,我們首頁定義了一個fn函數,裡面有個num預設為0,接著返回了一個匿名函數(也就是沒有名字的函數)。我們在外部用f接收這個返回的函數。這個匿名函數乾的事情就是把num加1,還有我們用來調試的alert。

  這裡之所以執行玩這個函數num沒有被銷毀是因為那個匿名函數的問題,因為這個匿名函數用到了這個num,所以沒有被銷毀,一直保持在記憶體中,因此我們f()時num可以一直加。

   這裡你可以看不懂了,之所以有這種感覺是因為js回收機制你不懂,強烈建議你看我之前的再次講解js中的回收機制是怎麼一回事。這篇文章。

 

   關於閉包的知識就到這裡了,如果你想看關於閉包的案例可以看這篇:從閉包案例中學習閉包的作用,會不會由你。

   而外:關於在for迴圈中綁定事件列印變數i是最後一次。

  

   而外說一句:這裡並不是說return就是閉包,這裡只是強調return的重要性,如果你還是一個新手建議你多看一些初級文章,在來看這篇文章,希望你會有新收穫。寫這篇文章一開始我也說了它的目的是回顧一下當初我沒有理解的地方,當初已經理解的這篇文章並沒有過多的去講。

 

 作用域竟然上面已經講完了~~~

   

   大前端 369451410歡迎你的加入。

 

   那就說一下this:

  我們經常用this,但是也許你還不清楚它是什麼吧?

     lis[i].onclick=function(){this.style.border="1px solid #ccc";} ;

     此時的this表示lis[?]它的引用。

     這裡的i不是i實際上是一個準確的數字:如lis[2].onclick = function(){this.style.border="1px solid #ccc";}; this = lis[2] ;   

     簡單來說this它始終引用一個對象。

       lis[2]它也一個對象,是一個HTMLElement對象。

       其實不管什麼情況下它都會有對象的,這個你不用操心,看

    function fn(){

     this.name = "追夢子";    

          };    

          fn();

          alert(this.name);//追夢子

          //當然也可以這樣

    alert(name);

           雖然這段代碼中看似沒有對象,但大錯特錯,因為瀏覽器環境中預設就有一個window對象,因此你在函數中直接用this.name實際上這個this就表示window。

  var json = {

    name:'yyy',

    fn:function(){alert(this.name)} 

    };

   json.fn(); // yyy;

  fn屬於json,所以this實際上就是json。

     如果你是初學者建議你暫時先記住這三點,當然this還有很多要說的,不過做為初學者你可以在項目中通過console.log來檢查this是否是你預期的那樣。

     更多關於this的內容,可以看徹底理解js中this的指向,不必硬背。

 

     這篇文章並不算是一篇入門的教程,這篇文章主要是總結之前沒有理解的地方,或者是以一種更加簡單明瞭的方式寫的,當然是按照我自己的理解來的,不一定你能理解,sorry,好了一切就從這裡結束吧。


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

-Advertisement-
Play Games
更多相關文章
  • 0.解決的問題 a.當選擇器語法沒有問題,找不到元素時,讓jquery報錯 b.選擇器語法有問題,程式無法繼續執行時,讓jquery報錯 主要針對傳遞字元串,嘗試前請備份jquery庫,最好改變名字加已區分. 1.環境配置 jquery-3.0.0.js未壓縮版 2.選擇器語法沒有問題,找不到元素 ...
  • 運行效果如下圖所示: ...
  • transform transition-origin:設置對象中變換所參照的原點 none:無變換 translate(<length>[,<length>]):指定對象的2D translation(2D平移)。第一個參數對應X軸,第二個參數對應Y軸。如果第二個參數未提供,則預設是為0. tra ...
  • 1. 使用簡單事件處理器 可以用幾種不同的方式處理事件。最直接的方式是用事件屬性創建一個簡單事件處理器(simple event handler)。元素為它們支持的每一種事件都定義了一個事件屬性。舉個例子,onmouseover事件屬性對應全局事件mouseover,後者會在用戶把游標移動到元素占據 ...
  • 隨著對分離HTML元素的語義重要性與其表現的影響的不斷強調,CSS在HTML5元素佈局方面的作用越來越重要。 1. 定位內容 控制內容最簡單的方式就是通過定位,這允許你使用瀏覽器改變元素的佈局方式。 1.1 設置定位類型 position 屬性設置了元素的定位方法。 position 屬性的不同值指 ...
  • 相對定位:position:relative; 不脫離文檔流,參考自身靜態位置通過top,bottom,left,right定位,並且可通過z-index進行層次分級。 絕對定位:position:absolute; 脫離文檔流,通過top,bottom,left,right定位,選取其最近的父級元 ...
  • 最近在項目中有好幾次遇到這個問題,感覺是浮動引起的,雖然用<div style="clear:both"></div>解決了,但自己不是特別明白,又在網上查了相關內容,是因為給li設置了浮動之後它就脫離當前正常的文檔流,所以沒辦法撐開外層ul的高度。 以下麵代碼為例,其實有好幾種解決方法,我用的這種 ...
  • <!DOCTYPE html><html><head> <title>duisgf</title> <meta charset="utf-8"><style type="text/css"> #image{ position: relative; left: 0px; top: 0px; }</st ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...