1. 程式人生 > >深入解析ES6中let和閉包

深入解析ES6中let和閉包

本篇文章主要介紹了深入理解ES6中let和閉包,寫的十分的全面細緻,具有一定的參考價值,對此有需要的朋友可以參考學習下。如有不足之處,歡迎批評指正。

本文介紹了深入理解ES6中let和閉包,分享給大家,具體如下:
在開始本文之前我們先來看一段程式碼

for(var i=0;i<10;i++){
  arr[i]=function(){
    return i;
  }
}
console.log(arr[3]());//10
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

顯然這段程式碼輸出10,並沒有向我們期望的返回3,原因也很簡單(js的變數提升)函式在呼叫時候訪問的是一個全域性作用域的i,此時for迴圈已經執行完畢,全域性變數i=10;
在ES5標準中,我們要想返回期望的3,通常的做法也很簡單,就是讓陣列中的每個函式有單獨的作用域,那麼我們只要構造一個立即執行函式即可(js中沒有塊級作用域,只區分函式作用域和全域性作用域)就像下面這樣:

var array=[];
for(var i=0;i<10;i++){
  array[i]=(function(i){
  return function(){
    return i;
    }
  })(i);
}
console.log(array[3]());//3
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

這樣一來陣列的每個函式就處於一個立即執行函式的函式作用域中,該立即執行函式傳入i,其實for迴圈執行了如下程式碼:

 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);
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

這樣一來,數字組中每個函式對應一個單獨的函式作用域(立即執行函式的)這裡共建立了10個函式作用域,這些函式作用域裡的i值就是執行時候傳入的0……9,當執行
array3;時候函式訪問的i值是其對應的立即執行函式作用域裡的 i,而不是全域性的i值,這樣我們就得到了預期的效果。
說得到這裡我們簡單來說一下閉包,閉包可以理解為一個閉包就是一個沒有釋放資源的棧區,棧區內的變數處於啟用狀態。上面的例子中for迴圈在執行時系統分配記憶體,js執行執行緒建立執行棧區,執行時候檢測到立即執行函式裡的變數i被內部函式引用,所以該棧區在記憶體中沒有被釋放,函式(陣列元素)被呼叫時候根據作用鏈首先訪問到的是上一級作用域(立即執行函式)的變數。
這裡不再詳細介紹閉包,如果想詳細瞭解閉包請閱讀《javascript高階程式設計》第7章
前面提到js中並沒有塊級作用域,只區分全域性作用域和函式作用域,在ES6中let實際是為js新增了塊級作用域,例如下面程式碼不用創造函式作用域就可以讓每個數組裡的函式訪問各自作用域裡的值:

let arr=[];
for(let i=0;i<10;i++){
  arr[i]=function(){
    return i;
  }
}
console.log(arr[3]());//3
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

可以看到我們並沒有像之前那樣構造一個函式作用域就能實現我們期望的效果,引入塊級作用域之後更方便我們書寫和理解程式碼,上述程式碼中for迴圈之後的{}是塊級作用域,每次迴圈時候每個返回的函式引用的是其對應塊作用域的變數,稍微改一下程式碼看著形象些:

let arr=[];
for(let i=0;i<10;i++){
  let k=i;
  arr[k]=function(){
    return k;
  }
}
console.log(arr[3]());//3
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

可見ES6引入塊作用域之後我們構造閉包函式更方便了。
這裡不多敘述let和const的相關內容,如果之前沒接觸ES6的小夥伴建議閱讀阮一峰老師的《ES6標準入門》。
在這裡再提一點,很多人看完概念之後,第一印象都是:“const 是表示不可變的值,而 let 則是用來替換原來的 var 的。”很多時候把let當做是var的替代品,凡是宣告變數就用let,你很可能寫出下面程式碼:

// 定義常量
const REG_GET_INPUT = /^\d{1,3}$/; 
// 定義配置項
let config = {
 isDev : false,
 pubDir: './admin/'
} 
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let CleanWebpackPlugin = require('clean-webpack-plugin');
//歡迎加入前端全棧開發交流圈一起吹水聊天學習交流:864305860

const 的定義是不可重新賦值的值,與不可變的值(immutable value)不同;const 定義的 Object,在定義之後仍可以修改其屬性。
所以其實他的使用場景很廣,包括常量、配置項以及引用的元件、定義的 “大部分” 中間變數等,都應該以cosnt做定義。反之就 let 而言,他的使用場景應該是相對較少的,我們只會在 loop(for,while 迴圈)及少量必須重定義的變數上用到他。
猜想:就執行效率而言,const 由於不可以重新賦值的特性,所以可以做更多語法靜態分析方面的優化,從而有更高的執行效率。

結語

感謝您的觀看,如有不足之處,歡迎批評指正。

本次給大家推薦一個免費的學習群,裡面概括移動應用網站開發,css,html,webpack,vue node angular以及面試資源等。
對web開發技術感興趣的同學,歡迎加入Q群:864305860,不管你是小白還是大牛我都歡迎,還有大牛整理的一套高效率學習路線和教程與您免費分享,同時每天更新視訊資料。
最後,祝大家早日學有所成,拿到滿意offer,快速升職加薪,走上人生巔峰。