一、關於變數宣告提升
在 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
,以最大化地避免錯誤的產生。
如果文章中有錯誤或表述不嚴謹的地方,歡迎指正。
也歡迎大家關注我的同名微信公眾號:李等等扣丁