在上一篇提到了JS有三種宣告變數的方式,分別是var
、const
及let
,var
和const
let
最大區別就是範圍(scope)的限制。所以在這一篇我們會詳談何謂範圍鏈及他們的覆寫優先順序。
我們先來看一個例子:
var globalVar = 'global';
function scopeFun(){
globalVar = "change in scopeFun";
console.log("1.",globalVar);//1. change in scopeFun
var funVar = 'Im in fun';
console.log("2.",funVar);//2. Im in fun
}
scopeFun();
console.log("3.",globalVar);//3. change in scopeFun
console.log("4.",funVar);//funVar is not defined
在function中所宣告的var
在全域是沒辦法作呼叫的,但是在全域宣告的在function中卻可以用。
這邊我們可以確定兩件事情:
var
是 函數級作用域(function-level scope)由function的{}
所區隔。那我們再來看ES6新增的 let
及const
的範圍:
let globalLet = true;
function scopeFun(){
if(globalLet){
let localLet = "local let";
const localConst = "local const";
console.log(localLet,localConst);
}
console.log(localLet,localConst);
}
scopeFun();
由這個例子我們可以得知:let
及const
的是區塊作用域(Blocak-level scope)由 {}
所區隔。
在講解變數覆寫優先順序前,我們還需要先了解什麼是 Hoisting:
在執行程式碼前,JS會把函式宣告放進記憶體裡面,可以在程式碼宣告該函式之前使用它。
function myName(name){
console.log("my name is "+name);
}
myName("John");//my name is John
一般在撰寫一個函式時候都會這樣作,但我們前面有提到說 可以在宣告該函式之前使用它,所以我們也可以這樣作:
myName("John");//my name is John
function myName(name){
console.log("my name is "+name);
}
當然 提升 也適用於 變數,但是跟函式就有很大的區別了。
如果我們在宣告前就先給初始化的話,是可以正常使用的:
price = 10;
price +=1;
console.log(price);//11
var price = 20;
但是如果在宣告後才初始化,則前面使用將會得到undefined
:
console.log(price);//undefined
var price = 20;
這段程式碼可以理解成這樣:
var price;
console.log(price);//undefined
var price = 20;
這邊要注意的是,ES6提供的變數宣告let
及const
是無法做到的,會回報錯誤:
console.log(price);//ReferenceError: price is not defined
let price= 20;
那如果我們用變數宣告函式的話,會發生什麼事情呢:
console.log(price);//undefined
price(20);//TypeError: price is not a function
var price = function (amount){
console.log(20*amount);
}
可以看到只有變數被提升到最上面且是undefined
,所以無法當成函式使用。
總結:
var
是 函數級作用域(function-level scope)由function的{}
所區隔。let
及const
的是區塊作用域(Blocak-level scope)由 {}
所區隔。var
也有提升,但如果使用時沒有初始化將會得到undefined
。var
宣告函式無法在之前使用,因為var
提升是undefined
。參考資料:
https://developer.mozilla.org/zh-TW/docs/Glossary/Hoisting
https://ithelp.ithome.com.tw/articles/10198485