ES6中let和閉包

  在開始本文以前咱們先來看一段代碼javascript

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

顯然這段代碼輸出10,並無向咱們指望的返回3,緣由也很簡單(js的變量提高)函數在調用時候訪問的是一個全局做用域的i,此時for循環已經執行完畢,全局變量i=10;html

在ES5標準中,咱們要想返回指望的3,一般的作法也很簡單,就是讓數組中的每一個函數有單獨的做用域,那麼咱們只要構造一個當即執行函數便可(js中沒有塊級做用域,只區分函數做用域和全局做用域)就像下面這樣:java

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循環執行了以下代碼:webpack

    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,當執行web

array[3]();時候函數訪問的i值是其對應的當即執行函數做用域裏的 i,而不是全局的i值,這樣咱們就獲得了預期的效果。數組

說獲得這裏咱們簡單來講一下閉包,閉包能夠理解爲一個閉包就是一個沒有釋放資源的棧區,棧區內的變量處於激活狀態。上面的例子中for循環在執行時系統分配內存,js執行線程建立執行棧區,執行時候檢測到當即執行函數裏的變量i被內部函數引用,因此該棧區在內存中沒有被釋放,函數(數組元素)被調用時候根據做用鏈首先訪問到的是上一級做用域(當即執行函數)的變量。閉包

  這裏再也不詳細介紹閉包,若是想詳細瞭解閉包請閱讀《javascript高級程序設計》第7章函數

  前面提到js中並無塊級做用域,只區分全局做用域和函數做用域,在ES6中let實際是爲js新增了塊級做用域,例以下面代碼不用創造函數做用域就可讓每一個數組裏的函數訪問各自做用域裏的值:oop

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: './admin/'
}

let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let CleanWebpackPlugin = require('clean-webpack-plugin');

 

   const 的定義是不可從新賦值的值,與不可變的值(immutable value)不一樣;const 定義的 Object,在定義以後仍能夠修改其屬性。

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

猜測:就執行效率而言,const 因爲不能夠從新賦值的特性,因此能夠作更多語法靜態分析方面的優化,從而有更高的執行效率。

因此上面代碼中,全部使用 let 的部分,其實都應該是用 const 的。

相關文章
相關標籤/搜索