<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          全網(wǎng)最通透的“閉包”認(rèn)知 · 跨越語言

          共 2719字,需瀏覽 6分鐘

           ·

          2021-04-06 16:59

          閉包作為前端面試的必考題目,常讓1-3年工作經(jīng)驗的JavaScripter感到困惑,其實主流語言都有閉包。

          今天我們深入聊一聊[閉包], 查缺補(bǔ)漏!

           1. 以面試題 ·  投石問路 2. 以C#閉包 ·  庖丁解牛 3.    跨越語言 ·追本溯源   ?  頭等函數(shù)   ?自由變量   ?詞法作用域4.  答面試題 · 返璞歸真

          1. 投石問路

          調(diào)用下面函數(shù),輸出結(jié)果是什么樣呢?

          static void Closure1(){   for (int i = 0; i < 5; i++)   {                      Task.Run(()=> Console.WriteLine(i));   }}//  輸出:55555

          是不是很意外?如何輸出原本預(yù)期的 0,1,2,3,4。

          bingo, 加一個臨時變量就可以解決。

          static void Closure2(){   for (int i = 0; i < 5; i++)   {      int j = i;      Task.Run(() => Console.WriteLine(j));   }}// 輸出:30142//  多次執(zhí)行的結(jié)果不一樣,但是總是會保持輸出 0,1,2,3,4 的亂序組合

          以上閉包概念涉及到 Task任務(wù),理解起來更加復(fù)雜,我們來看一個基礎(chǔ)的C#閉包。

          2. 庖丁解牛

          一個閉包就是一個“捕獲”了其生成的環(huán)境中、所引用的自由變量的函數(shù)。
          這個被引用的自由變量將和這個函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外。

           static void Closure() {    var x = 1;    Action action= () =>      {         var y = 1;         var result = x + y;         Console.WriteLine(result);         x++;      };    action();    action();}   // 輸出:  2  3

          我們首先定義了一個委托action,它引用了“x”變量(x變量既不是入?yún)ⅲ膊皇俏袃?nèi)的局部變量), 這個變量將被action"捕獲”,被自動添加到action 的運(yùn)行環(huán)境。

          當(dāng)我們執(zhí)行action時,原始的“x”已經(jīng)脫離了它被引用時的作用域環(huán)境,但是兩次執(zhí)行能輸出2,3 說明它脫離原引用環(huán)境仍然能用。

          當(dāng)你在代碼調(diào)試器(debugger)里觀察“action”時,可以看到C#編譯器為我們創(chuàng)建了一個Target屬性,里面封裝了 x 變量:

          源碼追溯,委托繼承自Delegate抽象類,Delegate類有個Target 屬性(獲取當(dāng)前委托調(diào)用實例方法的實例類) 。
          至此可以猜想: 我們每次執(zhí)行委托,實際是是執(zhí)行某個匿名類上的實例方法。

          都說了閉包是跨越語言的設(shè)計, 至少我知道 JavaScript C# Go都有閉包。

          3. 追本溯源

          閉包是詞法閉包的簡稱,維基百科上是這樣定義的:
          在計算機(jī)編程中,閉包是在詞法環(huán)境中綁定自由變量的頭等函數(shù)”。

          頭等函數(shù)

          頭等函數(shù)( First Class)意味著語言將其視為第一類數(shù)據(jù)類型的函數(shù), 意味著你可以將函數(shù)分配給一個變量(或作為參數(shù)傳遞),然后像正常函數(shù)一樣調(diào)用。

          很明顯,C#常使用的委托(C#委托的演進(jìn):匿名函數(shù)-->lambda表達(dá)式)是頭等函數(shù)。

          Func<string,string> myFunc = delegate(string var1)                                {                                    return "some value";                                   };Func<string,string> myFunc = var1 => "some value";  string myVar = myFunc("something");

          自由變量

          自由變量是在匿名函數(shù)/lambda表達(dá)式中被引用的變量,它不是函數(shù)的參數(shù)也不是函數(shù)的局部變量。

          var myVar = "this is good";Func<string,string> myFunc = delegate(string var1)                                {                                    return var1 + myVar;                                   };

          詞法作用域引用的自由變量,注意,是引用自由變量,并不是使用當(dāng)時自由變量的值

          ??通俗點, 就是告知這個變量環(huán)境,我這個匿名函數(shù)等會執(zhí)行時要用到這個變量;如果我沒被銷毀,你不能銷毀我引用的自由變量。

          我們再回過頭來看[投石問路]的面試題。

          4. 返璞歸真

          首先你要知道:循環(huán)內(nèi)開啟的Task任務(wù),并不保證執(zhí)行順序。

          Demo1:輸出5,5,5,5,5

          這是因為在 for循環(huán)內(nèi),開啟了5個Task任務(wù),每個任務(wù)均引用了自由變量i (相對于每個任務(wù)執(zhí)行環(huán)境,i 屬于全局變量);
          for循環(huán)先執(zhí)行完,i=5, 5個任務(wù)輸出時自然得到值5。

          為什么加上臨時變量就能輸出"預(yù)期"?

          Demo2:輸出亂序的0,1,2,3,4

          這是因為 在for循環(huán)內(nèi),每次循環(huán)j均拷貝自當(dāng)時的i,每個任務(wù)均引用了自由變量 j (每個任務(wù)執(zhí)行環(huán)境均維護(hù)了一個變量j);
          任務(wù)亂序執(zhí)行時依舊能獲取本任務(wù)綁定的自由變量j。


          有這樣的認(rèn)知,理解JavaScript 閉包也就不難了。

          # 總結(jié)

          本文屏蔽語言差異,理清了[閉包]的概念核心: 頭等函數(shù)、自由變量,不僅能幫助我們應(yīng)對多語種有關(guān)閉包的面試題, 也幫助我們了解[閉包]在通用語言中的設(shè)計初衷。

          原創(chuàng)不易 點個在看支持下~


          瀏覽 79
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩三级电影网站 | 国产性生活在线观看 | 一级a一级a爰片免费免免小说 | 国产精品97麻豆cm传媒 | 亚洲欧美日韩综合 |