2018-01-07 關(guān)于javascript閉包和作用域的理解

關(guān)于 javascript 閉包的一些思考

什么是作用域?

  • 作用域
    • 眾所周知 在javascript 作用域就是限制我們執(zhí)行代碼的一個(gè)范圍,或者說(shuō)是框架。
    • 首先來(lái)談?wù)刯s的編譯原理,其中不可避免的就要提到 引擎、編譯器、作用域
      • 引擎:負(fù)責(zé)整個(gè) JavaScript 程序的編譯及執(zhí)行過(guò)程
      • 編譯器:負(fù)責(zé)語(yǔ)法分析及代碼生成
      • 作用域: 負(fù)責(zé)收集并維護(hù)由所有聲明的標(biāo)識(shí)符(變量)組成的一系列查 詢,并實(shí)施一套非常嚴(yán)格的規(guī)則,確定當(dāng)前執(zhí)行的代碼對(duì)這些標(biāo)識(shí)符的訪問(wèn)權(quán)限
    • 這次我們的主角是==作用域==
    • 下面我們來(lái)看一個(gè)簡(jiǎn)單的賦值操作:

      var a = 2;
      
      • 然后他們?nèi)齻€(gè)都干了什么啦?
        • 變量的賦值操作會(huì)執(zhí)行兩個(gè)動(dòng)作,首先編譯器會(huì)在當(dāng)前作用域中聲明一個(gè)變量(如 果之前沒(méi)有聲明過(guò)),然后在運(yùn)行時(shí)引擎會(huì)在作用域中查找該變量,如果能夠找到就會(huì)對(duì) 它賦值。
    • 當(dāng)然我們不必深究他們到底干了什么,我們要深入探究 作用域到底是什么?

什么是詞法作用域?

  • 詞法作用域
    • 我們來(lái)先看看一段代碼

      function foo(a) { 
          var b = a * 2;
          function bar(c) { 
              console.log( a, b, c );
          }
          bar( b * 3 ); 
          
      }
      foo( 2 ); // 2, 4, 12
      
      • 1 包含著整個(gè)全局作用域,其中只有一個(gè)標(biāo)識(shí)符:foo。

      • 2 ?包含著 foo 所創(chuàng)建的作用域,其中有三個(gè)標(biāo)識(shí)符:a、bar 和 b。

      • 3 ?包含著 bar 所創(chuàng)建的作用域,其中只有一個(gè)標(biāo)識(shí)符:c。

    • 上面描述的就是作用域的作用,每個(gè)標(biāo)識(shí)符都對(duì)應(yīng)著相應(yīng)的。我們==把作用域看做一個(gè)氣泡==

什么是函數(shù)作用域?

  • 函數(shù)作用域
    • 如同上面的詞法作用域那樣,在 javascript 中當(dāng)我們創(chuàng)建一個(gè)函數(shù)的時(shí)候都會(huì)創(chuàng)建一個(gè)新的作用域。
    function foo(a){
        var b = 2;
        
        //一些代碼
        function bar(){
            // ...
        }
        
        // 更多的代碼
        
        var a = 3;
    }
    
    
    • 在這個(gè)代碼片段中,==foo(..) 的作用域氣泡中包含了標(biāo)識(shí)符 a、b、c 和 bar==。無(wú)論標(biāo)識(shí)符 聲明出現(xiàn)在作用域中的何處,這個(gè)標(biāo)識(shí)符所代表的變量或函數(shù)都將附屬于所處作用域的氣泡。

什么是塊作用域?

  • 塊作用域
    • 除 JavaScript 外的很多編程語(yǔ)言都支持塊作用域,因此其他語(yǔ)言的開(kāi)發(fā)者對(duì)于相關(guān)的思維 方式會(huì)很熟悉,但是對(duì)于主要使用 JavaScript 的開(kāi)發(fā)者來(lái)說(shuō),這個(gè)概念會(huì)很陌生。
      • 看下面的代碼
      for (var i=0; i<10; i++) { 
          console.log(i)
      }
      
      • 我們?cè)趂or的頭部定義了變量 i ,而且我們只想在for循環(huán)中使用 i ,而忽略了在 javascript 中 i 會(huì)綁定在全局變量(外部作用域)中。
      • 在 ES6 中我們推薦使用 let 來(lái)避免 i收到全局變量的污染

        for(let i = 0;i < 10; i++ ){
            console.log(i);
        }
        

什么是垃圾回收機(jī)制

  • 垃圾回收機(jī)制
    • JavaScript 垃圾回收的機(jī)制很簡(jiǎn)單:找出==不再使用的變量==,然后釋放掉其占用的內(nèi)存,但是這個(gè)過(guò)程不是時(shí)時(shí)的,因?yàn)槠溟_(kāi)銷比較大,所以垃圾回收器會(huì)按照固定的時(shí)間間隔周期性的執(zhí)行。
    • 那什么是==不再使用的變量==啦?
      • 我們知道js中的全局變量,和局部變量。全局變量在瀏覽器頁(yè)面卸載的時(shí)候才會(huì)回收。而局部變量在函數(shù)生命周期結(jié)束的時(shí)候?yàn)g覽器為了節(jié)約內(nèi)存空間,就需要回收這一變量。
    • 一種回收方法-標(biāo)記清除(mark and sweep)
      • 這是JavaScript最常見(jiàn)的垃圾回收方式,當(dāng)變量進(jìn)入執(zhí)行環(huán)境的時(shí)候,比如函數(shù)中聲明一個(gè)變量,垃圾回收器將其標(biāo)記為“進(jìn)入環(huán)境”,當(dāng)變量離開(kāi)環(huán)境的時(shí)候(函數(shù)執(zhí)行結(jié)束)將其標(biāo)記為“離開(kāi)環(huán)境”。
    • 還有其他的回收的方法就不多多探究了。

什么是閉包?

  • 閉包的理解
    • 作用域閉包

      • 參考阮一峰大神的文章,代碼中的f2函數(shù),就是閉包。
      function f1(){
         var n = 999;
         function f2(){
             alert(n);
         }
         return f2;
      }
      
      var result = f1();
      result();//999
      
      • 閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。

      • 由于在Javascript語(yǔ)言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,因此可以把閉包簡(jiǎn)單理解成"定義在一個(gè)函數(shù)內(nèi)部的函數(shù)"。

      • 所以,在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的一座橋梁。

    • 閉包的用途

      • 一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量
      • 另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中。
      function f1(){
      
          var n=999;
      
          nAdd=function(){n+=1}
      
          function f2(){
                alert(n);
          }
      
          return f2;  
          
      }
      
      var result=f1();
      
      result(); // 999
      
      nAdd();
      
      result(); // 1000
      
      • result實(shí)際上就是閉包f2函數(shù)。它一共運(yùn)行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數(shù)f1中的局部變量n一直保存在內(nèi)存中,并沒(méi)有在f1調(diào)用后被自動(dòng)清除。
      • 原因就在于f1是f2的父函數(shù),而f2被賦給了一個(gè)全局變量,這導(dǎo)致f2始終在內(nèi)存中,而f2的存在依賴于f1,因此f1也始終在內(nèi)存中,不會(huì)在調(diào)用結(jié)束后,被垃圾回收機(jī)制(garbage collection)回收。

參考:

你不知道的javascript(上)

學(xué)習(xí)Javascript閉包(Closure)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容