昨天我們聊了var的基本作用範圍,今天讓我們來介紹let/const的作用範圍,以及什麼是變數提升吧!
什麼是hoisting?直接讓們來看下面的範例:
console.log(a); //undefined
var a = 3;
我們在先宣告a變數以前,就先嘗試用console.log(a)來印出a是什麼。結果不是印出3也不是印出ReferenceError: a is not defined,而是印出undefined。這種現象就叫做 Hoisting,變數的宣告被「提升」到最上面去了。所以上面的範例你可以想像成這樣子:
var a;
console.log(a) //undefined
a = 3;
也因為有這種特性,強烈建議所有可能用到的變數都盡量在 scope 的最上面先宣告完成後再使用。
補充: 用「提升」去形容這現象是為了方便理解,事實上程式碼位置是不會變動的。
let 跟 const 是在ES6之後才有的變數宣吿。前面我們在介紹變數宣告有提過他們跟var的宣告差異,let/const宣告之前就存取變數或常數會噴ReferenceError的錯誤,而var會印出undefine。
let與const 的作用域是以區塊也就是{}大括號做區隔,var是function。看下列簡單範例:
{
var a = 1;
let b = 2;
const c =3;
}
console.log(a); //1
console.log(b); //ReferenceError: b is not defined
console.log(c); //ReferenceError: c is not defined
那let 與 const 宣告會有hoisting的現象嗎?
我們把上面hoisting範例改一下:
function double(num){
console.log(x) //ReferenceError: Cannot access 'x' before initialization
let x = 2;
return num * 2;
}
double(5);
乍看之下let並沒有提升的問題,不會印出undefined 而是直接噴ReferenceError: Cannot access 'x' before initialization的錯誤訊息。let/const的這個特性稱作為(Temporal Dead Zone, TDZ)。
那為什麼會說乍看之下沒有提升問題呢?
如果把範例再改一下:
var x = 10;
function double(num){
console.log(x) //ReferenceError: Cannot access 'x' before initialization
let x = 2;
return num * 2;
}
double(5);
從上面的範例結果,可以看的出來其實,let是有hoisting的特性的。那到底hoisting背後的原理是什麼呢?有興趣的朋友可以去翻翻ES3規格書的第十章:Execution Contexts。
最後我們來補充一下,「全域物件」是什麼?
其實我們常常在說的「全域變數」指的就是「全域物件」的屬性。看下面範例:
var a =10;
console.log(window.a); // 10
我們在最外層宣告變數a,一直以來我們都稱它「全域變數」,但從上面的結果可以發現,a其實是window物件下的ㄧ個屬性。所以,「全域變數」指的是「全域物件」的屬性。
以上就是今天的介紹!我們明天見!