<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>

          被譽為JavaScript中最難理解的概念之一的閉包是什么鬼?

          共 3292字,需瀏覽 7分鐘

           ·

          2023-06-20 10:13

          作者:?牛哥說我不優(yōu)雅

          https://juejin.cn/post/7218447209120006181

          一、閉包的概念

          當通過調(diào)用外部函數(shù)返回的內(nèi)部函數(shù)后,即使外部函數(shù)已經(jīng)執(zhí)行結(jié)束了,但是被內(nèi)部函數(shù)引用的外部函數(shù)的變量依然會保存在內(nèi)存中,我們把引用了其他函數(shù)作用域變量的函數(shù)和這些被引用變量的集合,稱為閉包(Closure),閉包是這些東西共同的組合

          在了解閉包的概念和用途之前,理解作用域和變量的生命周期等基礎(chǔ)預(yù)備知識,對于理解閉包非常有幫助。

          二、怎么實現(xiàn)閉包

          閉包是指一個函數(shù)可以訪問它定義時所在的詞法作用域以及全局作用域中的變量。在JavaScript中,閉包可以通過函數(shù)嵌套和變量引用實現(xiàn)。

          function?outerFunction()?{
          ????let?outerVariable?=?'我在outer函數(shù)里!';
          ??
          ????function?innerFunction()?{
          ??????console.log(outerVariable);
          ????}
          ??
          ????return?innerFunction;
          ??}
          ??
          ??const?innerFunc?=?outerFunction();
          ??innerFunc();?//?輸出:?我在outer函數(shù)里!

          在上面的代碼示例中,innerFunction引用了outerVariable,因此JavaScript引擎會保留outerFunction的作用域鏈,以便innerFunction可以訪問outerVariable

          function?a(){
          ????function?b(){
          ????????var?bb?=?888
          ????????console.log(aa);??//輸出:666
          ????}
          ????var?aa?=?666
          ????return?b
          }
          var?demo?=?a()
          demo()

          在上面的代碼示例中,a函數(shù)定義了一個名為aa的變量和一個名為b的函數(shù),b函數(shù)引用了aa變量,因此JavaScript引擎會保留a函數(shù)的作用域鏈,b函數(shù)可以訪問a函數(shù)的執(zhí)行上下文,b函數(shù)內(nèi)用到了外部函數(shù)a的變量aa,在a函數(shù)調(diào)用結(jié)束后該函數(shù)執(zhí)行上下文會銷毀,但會保留一部分留在內(nèi)存中供b函數(shù)使用,這就形成了閉包。

          具體來說,當內(nèi)部函數(shù)引用外部函數(shù)的變量時,外部函數(shù)的作用域鏈將被保留在內(nèi)存中,以便內(nèi)部函數(shù)可以訪問這些變量。這種函數(shù)嵌套和變量共享的方式就是閉包的核心概念。當一個函數(shù)返回另一個函數(shù)時,它實際上返回了一個閉包,其中包含了原函數(shù)定義時的詞法作用域和相關(guān)變量。

          三、閉包的用途

          1.封裝私有變量

          閉包可以用于封裝私有變量,以防止其被外部訪問和修改。封裝私有變量可以一定程度上防止全局變量污染,使用閉包封裝私有變量可以將這些變量限制在函數(shù)內(nèi)部或模塊內(nèi)部,從而減少了全局變量的數(shù)量,降低了全局變量被誤用或意外修改的風險。

          在下面這個例子中,調(diào)用函數(shù),輸出的結(jié)果都是1,但是顯然我們的代碼效果是想讓count每次加一的。

          function?add()?{
          ????let?count?=?0;
          ????count++;
          ????console.log(count);
          }
          add()???//輸出1
          add()???//輸出1
          add()???//輸出1

          一種顯而易見的方法是將count提到函數(shù)體外,作為全局變量。這么做當然是可以解決問題,但是在實際開發(fā)中,一個項目由多人共同開發(fā),你不清楚別人定義的變量名稱是什么,這么做有點冒險,有什么其他的辦法可以解決這個問題呢?

          function?add(){
          ????let?count?=?0
          ????function?a(){
          ????????count++
          ????????console.log(count);
          ????}
          ????return?a
          }
          var?res?=?add()?
          res()?//1?
          res()?//2
          res()?//3

          答案是用閉包。在上面的代碼示例中,add函數(shù)返回了一個閉包a,其中包含了count變量。由于count只在add函數(shù)內(nèi)部定義,因此外部無法直接訪問它。但是,由于a函數(shù)引用了count變量,因此count變量的值可以在閉包內(nèi)部被修改和訪問。這種方式可以用于封裝一些私有的數(shù)據(jù)和邏輯。

          2. 做緩存

          函數(shù)一旦被執(zhí)行完畢,其內(nèi)存就會被銷毀,而閉包的存在,就可以保有內(nèi)部環(huán)境的作用域。

          function?foo(){
          ????var?myName?='張三'
          ????let?test1?=?1
          ????const?test2?=?2?
          ????var?innerBar={
          ????????getName:?function(){
          ????????????console.log(test1);
          ????????????return?myName
          ????????},
          ????????setName:function(newName){
          ????????????myName?=?newName
          ????????}
          ????}
          ????return?innerBar
          }
          var?bar?=?foo()???
          console.log(bar.getName());?//輸出:1 張三
          bar.setName('李四')
          console.log(bar.getName());?//輸出:1 李四

          這里var bar = foo() 執(zhí)行完后本來應(yīng)該被銷毀,但是因為形成了閉包,所以導致foo執(zhí)行上下文沒有被銷毀干凈,被引用了的變量myName、test1沒被銷毀,閉包里存放的就是變量myName、test1,這個閉包就像是setName、getName的專屬背包,setName、getName依然可以使用foo執(zhí)行上下文中的test1和myName。

          3. 模塊化編程(實現(xiàn)共有變量)

          閉包還可以用于實現(xiàn)模塊化編程。模塊化編程是一種將程序拆分成小的、獨立的、可重用的模塊的編程風格。閉包可以用于封裝模塊的私有變量和方法,以便防止其被外部訪問和修改。例如:

          const?myModule?=?(function()?{
          ??let?privateVariable?=?'我是私有的!';

          ??function?privateMethod()?{
          ????console.log(privateVariable);
          ??}

          ??return?{
          ????publicMethod:?function()?{
          ??????privateMethod();
          ????}
          ??};
          })();

          myModule.publicMethod();?//?輸出:?我是私有的!

          在上面的代碼示例中,myModule實際上是一個立即執(zhí)行的匿名函數(shù),它返回了一個包含publicMethod的對象。在函數(shù)內(nèi)部,定義了一個私有變量privateVariable和一個私有方法privateMethod。publicMethod是一個公共方法,它可以訪問privateMethod,但是無法訪問privateVariable。這種方式可以用于實現(xiàn)簡單的模塊化編程。

          四、閉包的缺點

          閉包也存在著一個潛在的問題,由于閉包會引用外部函數(shù)的變量,但是這些變量在外部函數(shù)執(zhí)行完畢后沒有被釋放,那么這些變量會一直存在于內(nèi)存中,總的內(nèi)存大小不變,但是可用內(nèi)存空間變小了。一旦形成閉包,只有在頁面關(guān)閉后,閉包占用的內(nèi)存才會被回收,這就造成了所謂的內(nèi)存泄漏

          因此我們在使用閉包時需要特別注意內(nèi)存泄漏的問題,可以用以下兩種方法解決內(nèi)存泄露問題:

          1.及時釋放閉包:手動調(diào)用閉包函數(shù),并將其返回值賦值為null,這樣可以讓閉包中的變量及時被垃圾回收器回收。

          2.使用立即執(zhí)行函數(shù):在創(chuàng)建閉包時,將需要保留的變量傳遞給一個立即執(zhí)行函數(shù),并將這些變量作為參數(shù)傳遞給閉包函數(shù),這樣可以保留所需的變量,而不會導致其他變量的內(nèi)存泄漏。

          五、最后的話

          總之,閉包是一種非常重要的編程技術(shù),可以讓程序員更加靈活地處理數(shù)據(jù)和邏輯。在實際的開發(fā)過程中,合理地使用閉包可以幫助我們更加高效地編寫代碼,提高程序的性能和可維護性。



          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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毛A免费看 |