es6 - 塊級做用域

let const和塊級做用域

在js高程中,做者強調說js沒有塊級做用域。
然而,這種狀況在es6中發生了改變,es6經過在代碼塊中使用let, const引入了塊級做用域的特性。
下面是對此特性的介紹。es6

語法

es5做用域和變量提高

首先,在es5中,只有兩種做用域,函數做用域和全局做用域。 全部的變量和函數聲明都存在於這兩種做用域中。面試

js在執行時,會首先將函數定義和變量聲明提高到做用域的頂部,而初始化的代碼留在原處,這就是變量提高。 這是js語言與其餘語言不一樣的地方。閉包

塊級做用域與let const

  • 塊級做用域簡單來講就是使用{}包裹的一段代碼,函數,判斷,循環,甚至單獨的一個{}均可以看做一個塊級做用域。

在塊級做用域內部使用let, const聲明的變量,在塊做用域外部是不可見的。函數

  • 準確的說,使用const聲明的應該是一個常量,它的值是不可變的,應該在聲明時完成初始化。在後面對const聲明的變量賦值會致使錯誤。
  • 在同一個做用域中,使用let或const重複聲明變量是不被容許的。好比:
var count = 30;
let count = 20; //這裏不管順序,不管let或const,都會報錯。

//只有這種纔不會報錯
var count = 30;
var count = 20; //第二個var被忽略,count等於20
  • let, const聲明的變量並不會變量提高。另在,在做用域中,使用兩者聲明的變量存在一個暫時性死區TDZ,即在聲明語句前對變量的訪問和使用都會引起引用錯誤。好比:
if(condition){
    console.log(typeof value);//會報錯
    let value = 'icode007'
}

循環中的塊級綁定

js有一道經典的面試題,即在頁面插入10個a標籤,點擊每一個標籤時顯示相應的序號。或者是:es5

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

這道題常常用來講明變量的做用域和閉包的相關問題。由於全部的函數引用的都是同一個i,因此都顯示10.
正確的代碼是使用當即執行函數,利用閉包特性:指針

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

經過閉包,每一個函數調用的其實是其獨有的i。code

然而,在es6,有個更好的方案,使用let。只需將第一段代碼i聲明中var換成let便可。對象

在for循環中,每次迭代let都會建立一個新的同名變量,並進行初始化,至關於上面使用當即執行函數的行爲。在for-in循環和for-of循環中,一樣如此。作用域

注意事項

const聲明的變量是不可變的,其實質是變量所引用的指針不能發生變化,但因爲js動態語言的本質,當const聲明一個對象時,對對象的改變是容許的。好比:it

const obj = {name: 'icode'};
obj.name ='thoms'; //不會發生錯誤
obj = {name: "thoms"} //發生錯誤

在for-in和for-of迭代中使用const與使用let的行爲相同,前提是再也不代碼塊中改變它的值,在for循環中,因爲i++會改變變量的值,因此會報錯。

在以前全局中使用var定義的變量會成爲window對象的一個屬性,而在全局中使用let, const定義的變量不會成爲window對象的屬性。

最佳實踐

推薦的最佳實踐是儘可能使用let而不是使用var去定義變量,這能讓咱們代碼更加的規範。

更加推薦的作法是通常使用const定義變量,只有在預期變量會發生改動時才使用let來定義。由於大部分變量定義後是無需發生變化的。這種方式能減小代碼出錯的概率。

相關文章
相關標籤/搜索