重讀《深入理解ES6》 —— 塊級作用域
在 ES5 中,我們通常會使用 var
來宣告變數。在使用 var
宣告變數的時候,通常會遇到變數宣告提升的問題。這種機制會讓很多初學者疑惑不解。其實當我們理解了一個變數通常包括 宣告 和 賦值 兩個部分,這個問題也就不難理解了。
// 1 console.log(a); // undefined var a = 3; // 2 function foo() { console.log(b);// undefined if (true) { var b = 2; } } 複製程式碼
事實上,無論在全域性作用域或者函式作用域中,只要通過 var
關鍵字宣告的變數,不論在哪裡宣告,都會被當成在當前作用域頂部宣告的變數。
// 1 var a; console.log(a); a = 3; // 2 function foo() { var b; console.log(b); if (true) { b = 2; } } 複製程式碼
二、塊級作用域
其實,變數提升的機制,不太符合我們的編碼習慣,我們常常希望程式碼能夠按照順序執行,這也符合一般人的邏輯習慣。為此 ES6 引入了塊級作用域的概念。
塊級作用域其實就是詞法作用域,我們的程式碼寫在哪,就會在哪裡執行,這更符合我們的程式設計習慣。我們常說的塊包括 函式內部 和 {}之間的部分 。
為了實現塊級作用域,ES6 採用 let
和 const
代替 var
來宣告變數。用 let
和 const
宣告的變數會把變數的作用域限制在當前的程式碼塊中,並且宣告的變數不會被提升。另外,用 let
宣告的變數,在同一程式碼塊內,禁止重複宣告。
// 1、變數不會提升 console.log(a); // ReferenceError: a is not defined let a = 3; // 2、變數只能在當前作用域訪問 if (true) { const b = 3; console.log(b); // 3 } console.log(b); // ReferenceError: b is not defined // 3、禁止重複宣告 function foo() { let c = 3; let c = 4; // Identifier 'c' has already been declared } foo(); 複製程式碼
三、let 與 const 的區別
用 let
和 const
都可以建立一個塊級作用域,唯一的區別是 const
用來宣告一個常量,它的值一旦被設定後不可修改。所以,用 const
宣告的常量必須初始化。
// 1、不可更改 const a = 1; a = 2; // TypeError: Assignment to constant variable. // 2、必須初始化 const b; // SyntaxError: Missing initializer in const declaration 複製程式碼
關於 const
宣告的變數不可修改,有一個值得注意的地方就是用 const
宣告一個物件。比如:
const tom = { age: 18, city: 'shanghai' }; tom.age = 19; // 這是可以的 複製程式碼
我們可以理解為,用 const
聲明瞭一個變數 tom,將一個物件的引用地址賦值給變數 tom,只要這個引用地址不發生變化,內部的值是可以修改的。
四、迴圈中塊級作用域
在 ES5 中,比較讓人頭疼的地方可能就是 for 迴圈了。在迴圈中,我們用 var
宣告一個變數,迴圈結束後,我們其實是希望這個變數被銷燬的。但由於 var
宣告的變數具有宣告提升的特性,所以當我們用 for 迴圈的時候,往往會汙染我們的全域性作用域。
for (var i = 0; i < 10; i++) { // do something } console.log(i); // 10 // 當迴圈結束的時候,其實我們是希望變數 i 可以被銷燬的。 // 但其實它被留在了全域性 複製程式碼
這個時候,我們使用 let
來宣告迴圈中的變數,就可以輕易的解決這個問題。
for (let i = 0; i < 10; i++) { // do something } console.log(i); // ReferenceError: i is not defined // 可以看到,迴圈結束,變數 i 就被銷燬了。 perfect~~ 複製程式碼
最後總結一下, let
和 const
幫助我們解決了不少問題,我們不會再為變數提升引發的種種問題而困惑了,同時在迴圈中使用 let
來代替 var
可以在迴圈結束的時候銷燬變數,避免無用的變數影響全域性。而當前使用塊級繫結的最佳實踐是:預設使用 const
,只在確定需要改變變數的值時,使用 let
,以最大化地避免錯誤的產生。
如果文章中有錯誤或表述不嚴謹的地方,歡迎指正。
也歡迎大家關注我的同名微信公眾號:李等等扣丁
