首頁 >web前端 >js教程 >在ES6中詳細解讀let和閉包

在ES6中詳細解讀let和閉包

亚连
亚连原創
2018-06-05 16:15:441438瀏覽

本篇文章主要介紹了深入理解ES6中let和閉包,現在分享給大家,也給大家做個參考。

本文介紹了深入理解ES6中let和閉包,分享給大家,具體如下:

#在開始本文之前我們先來看一段程式碼

for(var i=0;i<10;i++){
  arr[i]=function(){
    return i;
  }
}
console.log(arr[3]());//10

顯然這段程式碼輸出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

這樣一來數組的每個函數就處於一個立即執行函數的函數作用域中,該立即執行函數傳入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);
……

這樣一來,數字組中每個函數對應一個單獨的函數作用域(立即執行函數的)這裡共創建了10個函數作用域,這些函數作用域裡的i值就是執行時候傳入的0……9,當執行

array[3]();時候函數存取的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

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

let arr=[];
for(let i=0;i<10;i++){
  let k=i;
  arr[k]=function(){
    return k;
  }
}
console.log(arr[3]());//3

可見ES6引入塊作用域之後我們建構閉包函數更方便了。

這裡不多敘述let和const的相關內容,如果之前沒接觸ES6的朋友建議閱讀阮一峰老師的《ES6標準入門》。

在這裡再提一點,很多人看完概念之後,第一印像都是:「const 是表示不可變的值,而let 則是用來替換原來的var 的。」很多時候把let當做是var的替代品,凡是宣告變數就用let,你很可能寫出下面程式碼:

 // 定义常量
const REG_GET_INPUT = /^\d{1,3}$/;

// 定义配置项
let config = {
 isDev : false,
 pubDir: &#39;./admin/&#39;
}

let path = require(&#39;path&#39;);
let HtmlWebpackPlugin = require(&#39;html-webpack-plugin&#39;);
let CleanWebpackPlugin = require(&#39;clean-webpack-plugin&#39;);

const 的定義是不可重新賦值的值,與不可變的值(immutable value)不同;const 定義的Object,在定義之後仍可以修改其屬性。

所以其實他的使用場景很廣,包括常數、配置項目以及引用的元件、定義的 「大部分」 中間變數等,都應該以cosnt做定義。反之就 let 而言,他的使用場景應該是相對較少的,我們只會在 loop(for,while 循環)及少量必須重定義的變數上用到他。

猜想:就執行效率而言,const 由於不可以重新賦值的特性,所以可以做更多語法靜態分析方面的最佳化,從而有更高的執行效率。

所以上面程式碼中,所有使用 let 的部分,其實都應該是用 const 的。

上面是我整理給大家的,希望今後對大家有幫助。

相關文章:

詳細說明在vue2中使用axios解決http請求出現的問題(詳細教學)

透過在vue在專案中引入highcharts圖表的方法有哪些?

在Angular中@HostBinding()和@HostListener()用法(詳細教學)

以上是在ES6中詳細解讀let和閉包的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn