本文介紹了深入理解ES6中l(wèi)et和閉包,分享給大家,具體如下:
在開始本文之前我們先來看一段代碼
for(var i=0;i<10;i++){ arr[i]=function(){ return i; }}console.log(arr[3]());//10顯然這段代碼輸出10,并沒有向我們期望的返回3,原因也很簡單(js的變量提升)函數(shù)在調用時候訪問的是一個全局作用域的i,此時for循環(huán)已經(jīng)執(zhí)行完畢,全局變量i=10;
在ES5標準中,我們要想返回期望的3,通常的做法也很簡單,就是讓數(shù)組中的每個函數(shù)有單獨的作用域,那么我們只要構造一個立即執(zhí)行函數(shù)即可(js中沒有塊級作用域,只區(qū)分函數(shù)作用域和全局作用域)就像下面這樣:
var array=[];for(var i=0;i<10;i++){ array[i]=(function(i){ return function(){ return i; } })(i);}console.log(array[3]());//3這樣一來數(shù)組的每個函數(shù)就處于一個立即執(zhí)行函數(shù)的函數(shù)作用域中,該立即執(zhí)行函數(shù)傳入i,其實for循環(huán)執(zhí)行了如下代碼:
array[0]=(function(i){ return function(){ return i; } })(0); array[1]=(function(i){ return function(){ return i; } })(1); array[2]=(function(i){ return function(){ return i; } })(2);……這樣一來,數(shù)字組中每個函數(shù)對應一個單獨的函數(shù)作用域(立即執(zhí)行函數(shù)的)這里共創(chuàng)建了10個函數(shù)作用域,這些函數(shù)作用域里的i值就是執(zhí)行時候傳入的0……9,當執(zhí)行
array[3]();時候函數(shù)訪問的i值是其對應的立即執(zhí)行函數(shù)作用域里的 i,而不是全局的i值,這樣我們就得到了預期的效果。
說得到這里我們簡單來說一下閉包,閉包可以理解為一個閉包就是一個沒有釋放資源的棧區(qū),棧區(qū)內的變量處于激活狀態(tài)。上面的例子中for循環(huán)在執(zhí)行時系統(tǒng)分配內存,js執(zhí)行線程創(chuàng)建執(zhí)行棧區(qū),執(zhí)行時候檢測到立即執(zhí)行函數(shù)里的變量i被內部函數(shù)引用,所以該棧區(qū)在內存中沒有被釋放,函數(shù)(數(shù)組元素)被調用時候根據(jù)作用鏈首先訪問到的是上一級作用域(立即執(zhí)行函數(shù))的變量。
這里不再詳細介紹閉包,如果想詳細了解閉包請閱讀《javascript高級程序設計》第7章
前面提到js中并沒有塊級作用域,只區(qū)分全局作用域和函數(shù)作用域,在ES6中l(wèi)et實際是為js新增了塊級作用域,例如下面代碼不用創(chuàng)造函數(shù)作用域就可以讓每個數(shù)組里的函數(shù)訪問各自作用域里的值:
let arr=[];for(let i=0;i<10;i++){ arr[i]=function(){ return i; }}console.log(arr[3]());//3可以看到我們并沒有像之前那樣構造一個函數(shù)作用域就能實現(xiàn)我們期望的效果,引入塊級作用域之后更方便我們書寫和理解代碼,上述代碼中for循環(huán)之后的{}是塊級作用域,每次循環(huán)時候每個返回的函數(shù)引用的是其對應塊作用域的變量,稍微改一下代碼看著形象些:
新聞熱點
疑難解答
圖片精選