欧美性猛交xxx嘿人猛交_又色又爽又高潮免费观看_精品国产一区二区三区久久影院_青娱乐极品视觉盛宴国产视频

技術頻道導航
HTML/CSS
.NET技術
IIS技術
PHP技術
Js/JQuery
Photoshop
Fireworks
服務器技術
操作系統
網站運營

贊助商

分類目錄

贊助商

最新文章

搜索

一個示例一行行代碼理解JS閉包是如何執行的

作者:admin    時間:2022-6-7 17:19:34    瀏覽:

JavaScript 中的閉包是許多人難以理解的概念之一。在接下來的文章中,我將清楚地解釋什么是閉包,并且我將使用簡單的代碼示例來說明這一點。

什么是閉包?

閉包是 JavaScript 中的一項功能,其中內部函數可以訪問外部(封閉)函數的變量——作用域鏈。

閉包具有三個作用域鏈:

  • 它可以訪問自己的范圍——在大括號之間定義的變量
  • 它可以訪問外部函數的變量
  • 它可以訪問全局變量

對于新手來說,這個定義似乎不好理解。不過沒關系,下面會通過簡單的示例說明,新手也可很快理解它。

真正的閉包是什么?

讓我們看一個 JavaScript 中的簡單閉包示例:

function outer() {
   var b = 10;
   function inner() {
        
         var a = 20; 
         console.log(a+b);
    }
   return inner;
}

這里我們有兩個函數:

  • outer()是具有變量b的外部函數,并返回inner函數。
  • inner()是一個內部函數,它的變量a被調用,并在其函數體內訪問outer()的一個變量b

變量b的作用域僅限于outer函數,變量a的作用域僅限于inner函數。

現在讓我們調用outer()函數,并將結果存儲在一個變量X中。然后我們再次調用outer()函數并將其存儲在變量Y中。

function outer() {
   var b = 10;
   function inner() {
        
         var a = 20; 
         console.log(a+b);
    }
   return inner;
}
var X = outer(); //outer() 第一次調用
var Y = outer(); //outer() 第二次調用

讓我們一步一步地看看outer()函數第一次被調用時會發生什么:

  • 變量b已創建,其范圍僅限于outer()函數,其值設置為10
  • 下一行是一個函數聲明,所以沒有什么要執行的。
  • 在最后一行,return inner查找名為inner的變量,發現該變量inner實際上是一個函數,因此返回整個函數體inner
  • [請注意,該return語句不執行內部函數, 一個函數僅在后跟()時執行,而是該return語句返回函數的整個主體。]
  • return 語句返回的內容存儲在X中,因此,X將存儲以下內容:
    function inner() {
      var a=20;
      console.log(a+b);
    }
  • 函數outer()執行完畢,現在outer()范圍內的所有變量都不存在了。

最后一部分很重要,需要理解。一旦函數完成執行,在函數范圍內定義的任何變量都將不復存在。

在函數內部定義的變量的生命周期就是函數執行的生命周期。

這意味著在console.log(a+b)中,變量b僅在outer()函數執行期間存在。一旦outer函數完成執行,變量b就不再存在。

當函數第二次執行時,函數的變量會被再次創建,直到函數完成執行。

因此,當outer()第二次調用時:

  • 創建了一個新變量b,其范圍僅限于outer()函數,其值設置為10
  • 下一行是一個函數聲明,所以沒有什么要執行的。
  • return inner返回整個函數體inner
  • return 語句返回的內容存儲在Y中。
  • 函數outer()執行完畢,現在outer()范圍內的所有變量都不存在了。

這里重要的一點是,當outer()第二次調用函數時,b會重新創建變量。此外,當outer()函數第二次完成執行時,這個新變量b再次不復存在。

這是要實現的最重要的一點。函數內部的變量只有在函數運行時才存在,一旦函數執行完畢就不再存在。

現在,讓我們回到我們的代碼示例,看看XY。由于outer()函數在執行時返回一個函數,因此變量XY是函數。

這可以通過在 JavaScript 代碼中添加以下內容來輕松驗證:

console.log(typeof(X)); //X 是類型函數
console.log(typeof(Y)); //Y 是類型函數

由于變量XY是函數,我們可以執行它們。在 JavaScript 中,可以通過()在函數名稱后添加來執行函數,例如X()Y()

function outer() {
var b = 10;
   function inner() {
        
         var a = 20; 
         console.log(a+b);
    }
   return inner;
}
var X = outer(); 
var Y = outer(); 
// outer()函數執行完畢
X(); // X() 第一次調用
X(); // X() 第二次調用
X(); // X() 第三次調用
Y(); // Y() 第一次調用

demodownload

當我們執行X()Y()時,我們本質上是在執行inner函數。

讓我們逐步檢查X()第一次執行時會發生什么:

  • 創建了變量a,并將其值設置為20
  • JavaScript 現在嘗試執行a + b,JavaScript 知道a的存在,因為它剛剛創建它。但是,變量b不再存在。由于b是外部函數的一部分,b因此僅在outer()函數執行時存在。由于outer()函數在我們調用X()之前就完成了執行,因此outer函數范圍內的任何變量都不再存在,因此變量b也不再存在。

由于 JavaScript 中的閉包,該inner函數可以訪問封閉函數的變量。換句話說,inner函數在執行封閉函數時保留封閉函數的作用域鏈,因此可以訪問封閉函數的變量。

在我們的示例中,inner函數保存了outer()函數執行b=10時的值,并繼續保存(關閉)它。

它現在引用它的作用域鏈,并注意到b在其作用域鏈中確實具有變量的值,因為它在outer函數執行b時將值封閉在閉包中。

因此,JavaScript 知道a=20b=10,并且可以計算a+b

你可以通過在上面的示例中添加以下代碼行來驗證這一點:

function outer() {
var b = 10;
   function inner() {
        
         var a = 20; 
         console.log(a+b);
    }
   return inner;
}
var X = outer(); 
console.dir(X); //使用 console.dir() 代替 console.log()

在控制臺,你可以展開元素以實際查看閉包元素(如下面倒數第四行所示)。請注意,即使在outer()函數完成執行后, 閉包的值b=10也會保留。

 變量 b=10 保存在閉包中
變量 b=10 保存在閉包中

現在讓我們重新回顧一下我們在開始時看到的閉包的定義,看看它現在是否更有意義。

所以內部函數有三個作用域鏈:

  • 訪問自己的范圍——變量a
  • 訪問outer函數的變量——變量b
  • 訪問可能定義的任何全局變量 

進一步了解閉包

為了深入了解閉包,讓我們通過添加三行代碼來擴充示例:

function outer() {
var b = 10;
var c = 100;
   function inner() {
        
         var a = 20; 
         console.log("a= " + a + " b= " + b);
         a++;
         b++;
    }
   return inner;
}
var X = outer();  // outer() 第一次被調用
var Y = outer();  // outer() 第二次被調用
//outer()函數執行完畢
X(); // X() 第一次調用
X(); // X() 第二次調用
X(); // X() 第三次調用
Y(); // Y() 第一次調用

demodownload

輸出

a=20 b=10
a=20 b=11
a=20 b=12
a=20 b=10

 

讓我們一步一步地檢查這段代碼,看看到底發生了什么,看看閉包的實際效果!

var X = outer();  // outer()第一次調用

outer()第一次調用,執行以下步驟:

  • 創建變量b,并設置為10;
    創建變量c,并設置為100。
    我們在引用中調用b(第一次)c(第一次)
  • 此時返回inner函數并賦給X,變量b作為閉包以b=10包含在inner函數作用域鏈中,因為inner使用了變量b
  • outer函數完成執行,其所有變量不再存在。變量c不再存在,盡管變量b作為閉包存在于inner中。

 

var Y= outer();  // outer()第二次調用
  • 重新創建變量b,并設置為10;
    重新創建變量c,并設置為100;
    請注意,即使變量之前執行過一次并且不再存在,一旦函數完成執行,它們就會被創建為全新的變量。
    我們調用b(第二次)和c(第二次)作為我們的引用。
  • 此時返回inner函數并賦給Y,變量b作為閉包以b(第二次)=10包含在inner函數作用域鏈中,因為inner使用了變量b
  • outer函數完成執行,其所有變量不再存在。
    變量c(第二次)不再存在,盡管變量b(第二次)作為閉包存在于inner中。

現在讓我們看看執行以下代碼行時會發生什么:

X(); // X() 第一次調用
X(); // X() 第二次調用
X(); // X() 第三次調用
Y(); // Y() 第一次調用

X()第一次調用時,

  • 變量a被創建,并設置為20。
  • a的值=20, b的值來自閉包值,b(第一次), 所以b=10
  • 變量ab都遞增1。
  • X()完成執行,其所有內部變量(變量a)不再存在。
    但是,b(第一次)被保存為閉包,所以b(第一次)繼續存在。

X()第二次調用時,

  • 變量a被重新創建,并設置為20。
  • 變量a任何先前的值不再存在,因為它在X()第一次完成執行時不再存在。
  • a的值=20;b的值取自閉包值b(第一次),還要注意,我們在上一次執行中增加了b的值,所以b=11
  • 變量ab再次遞增1。
  • X()完成執行并且它的所有內部變量(變量 a ) 不再存在。
    但是,b(第一次)隨著閉包繼續存在而被保留。

X()第三次調用時,

  • 變量a被重新創建,并設置為20;
    變量a任何先前的值不再存在,因為它在X()第二次完成執行時不再存在。
  • b的值來自閉包值——b(第一次)
    還要注意我們在之前的執行中為b的值增加了1, 所以b=12
  • 變量ab再次遞增1。
  • X()完成執行,其所有內部變量 (變量a)不再存在。
    但是,b(第一次)隨著閉包繼續存在而被保留。

第一次調用 Y() 時,

  • 變量a被重新創建,并設置為20;
    a的值=20, b的值來自閉包值—— b(第二次),所以b=10
  • 變量ab均遞增1。
  • Y()完成執行,它的所有內部變量(變量a)不再存在。
    但是,b(第二次)被保存為閉包,所以b(第二次)繼續存在。

結束語

閉包是 JavaScript 中一開始難以掌握的微妙概念之一。但是一旦你理解了它們,你就會意識到事情并沒有那么復雜難懂。

相關文章

標簽: 閉包  
x