爲什麼ES6不鼓勵用var聲明變量了
在函數作用域或全局作用域中通過關鍵字var聲明的變量,無論實際上是在哪裏聲明的,都會被當成是在當前作用域頂部聲明的變量。
- 舉個栗子:
function getValue(condition){
if(condition){
var value = "blue";
return value;
}
else{
return null;
}
}
這段代碼按正常的眼光來看待,只有當condition的值爲true的時候,變量value纔會被創建,但是實際上,無論condition的值是什麼,變量value都會被創建。在預編譯階段,JavaScript引擎會將上面的代碼修改成這樣。
function getValue(condition){
var value;
if(condition){
value = "blue";
return value;
}
else{
return null;
}
}
正如我在開頭所說的那樣,變量value 的聲明被提升到了函數的頂部,但是賦值操作卻依然在原處執行,這也就意味着,在else字句裏,value變量也是能被訪問到的,但是因爲沒有賦值,所以得到的結果是undefined。
這個機制被稱爲 變量提升(Hoisting)機制。
塊級聲明
塊級聲明用於聲明在指定塊的作用域之外無法訪問的變量。塊級作用域存在於:
- 函數內部
- 塊中1
簡單來說就是用塊級聲明所聲明的變量只能在該代碼塊中發揮作用。
let聲明
let聲明是塊級聲明,let聲明在用法上和var是一樣的,用let代替var來聲明變量可以把變量的作用域限制在當前代碼塊中。let聲明是不存在變量提升機制的,因此用let聲明變量時一般把聲明語句放在代碼塊的頂部,以便整個代碼塊都可以訪問到該變量。
舉個栗子:
function getValue(condition){
if(condition){
let value = "blue";
return value;
}
else{
//變量value在這裏是不存在的
return null;
}
//變量value在這裏是不存在的
}
let的禁止重聲明:如果作用域中已經存在某個標識符,此時再使用let來試圖聲明它就會報錯。
舉個栗子:
var a = 1;
let a = 2;
此時let不會給a賦值爲2,而是會拋出錯誤,因爲在一個作用域中不能用let重複定義已經存在的標識符。
var a = 1;
if(condition){
let a = 2;
}
這樣聲明變量是不會報錯的,因爲它們不在同一個作用域中,所以不存在重聲明的問題。
const聲明
const聲明是塊級聲明,使用const聲明得到的不是變量而是常量,其值被初始化之後就不可以更改,這也意味着使用const聲明常量必須進行初始化操作,如果用const聲明常量時沒有賦值將會拋出語法錯誤。
舉個栗子:
const my_name = "炒米粉";
//語法錯誤,常量未初始化。
const my_age;
//語法錯誤,常量的值不能被改變
my_name = "炒河粉";
值得一提的是,const也是禁止重聲明的,這點與let一致,這裏就不贅述了。
用const聲明對象:用const來聲明對象的話是不允許修改綁定關係的,但是允許修改對象的屬性值。
舉個栗子:
const boy = {
name:"炒米粉"
};
//修改對象屬性的值是沒有問題的
boy.name = "帥氣的炒米粉";
//拋出語法錯誤
boy = {
name:"帥氣的炒米粉"
};
臨時死區(Temporal Dead Zone)
JavaScript引擎在掃描代碼發現聲明的時候,要麼將聲明提升到作用域頂部(var的變量提升機制),要麼將聲明放入TDZ中(遇到let或const)。
訪問TDZ中的變量將會拋出錯誤,當執行過變量聲明語句後,該變量纔會從TDZ中移出。
舉個栗子:
//num的TDZ起點
console.log("DO SOMETHING");
console.log(typeof num);
//num的TDZ終點
let num = 1;
上面的代碼是會報錯的,因爲第二行代碼仍處於num的TDZ中,卻訪問了num。
上面的栗子用的是let,如果換成const結果也是一樣的。
相比上面的代碼,這一段反而不會報錯:
console.log(typeof num);//"undefined"
if(condition){
let num = 1;
}
因爲第一行代碼是試圖訪問當前作用域中並不存在的變量,所以得到的是undefined,而不會報錯。
塊的定義:在字符 { 和 } 之間的區域 ↩︎