在js高程中,做者強調說js沒有塊級做用域。
然而,這種狀況在es6中發生了改變,es6經過在代碼塊中使用let, const引入了塊級做用域的特性。
下面是對此特性的介紹。es6
首先,在es5中,只有兩種做用域,函數做用域和全局做用域。 全部的變量和函數聲明都存在於這兩種做用域中。面試
js在執行時,會首先將函數定義和變量聲明提高到做用域的頂部,而初始化的代碼留在原處,這就是變量提高。 這是js語言與其餘語言不一樣的地方。閉包
在塊級做用域內部使用let, const聲明的變量,在塊做用域外部是不可見的。函數
var count = 30; let count = 20; //這裏不管順序,不管let或const,都會報錯。 //只有這種纔不會報錯 var count = 30; var count = 20; //第二個var被忽略,count等於20
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來定義。由於大部分變量定義後是無需發生變化的。這種方式能減小代碼出錯的概率。