無關鍵字賦值、var宣告、let宣告最大的差別在於生存區域的不同。
無關鍵字賦值 這意味著全域變數的宣告,當然你在全域範圍使用var/let宣告也是全域的。只是無關鍵字可能引發意外的情況,像是你預期變數應該是函數區域的:
function printG(){
g = 1
console.log(`printG: `, g)
}
printG() // => printG: 1
console.log(`Global G:`, g) // => Global G: 1
上例中全域情況也取得到在printG函數裏定義的全域變數。這相當於你顯式定義g於全域:
var g = 0
function printG(){
g = 1
console.log(`printG: `, g)
}
printG() // => printG: 1
console.log(`Global G:`, g) // => Global G: 1
對於printG來看,就是去外部找一個g來用,找不到就在全域建立一個。
var宣告 透過var宣告的變數,其生存範圍存在於函數內:
function printV1(){
var v = 2
console.log(printV1:
, v)
}
printV1() // => pritnV1: 2
try{
console.log(v)// error
} catch {
console.log('not find v');
}
所以不同於g的情況,v並不會因爲printV1存在於全域。(printV1裏的v並不會影響到全域,同樣,如果你全域有宣告v的話,亦不會影響到printV1裏的v)
此外,var的宣告是屬於函數內的,就算下面這樣寫也沒有問題:
function printV3(){
if(true) {
var v = 2
}
console.log(printV3:
, v)
}
printV3() // => pritnV3: 2
而且你只要再函式內宣告,就不會有問題。所以下面情況也不會報錯:
function printV2(){
console.log(printV2:
, v)
var v = 2
}
printV2() // => undefined
你甚至可以使用var多次宣告:
function printV2(){
console.log(printV2:
, v)
var v = 2
var v = 3
var v = 4
}
printV2() // => undefined
let宣告
使用let宣告,和var宣告很像,但生存區域更小一些,變數是屬於區塊的(block)。同樣不會影響到全域的變數狀態:
function printL1(){
let l = 3;
console.log(printL1:
, l);
}
printL1() // => printL1: 3
try{
console.log(Global l:
, l); //error
} catch {
console.log(not find l
);
}
不同的是不能像printV3在函式任意位置宣告:
function printL3(){ if(true){ let l = 3 }
try {
console.log(printL2:
, l)
} catch {
console.log(can't find l in printL3
)
}
}
printL3() // => can't find l in printL2
而且存在暫時執行死區(TDZ)。不能在宣告前使用,不能多次宣告(內部區塊覆蓋外部區塊可以)。
function printL2() { console.log(l) let l = 3 }
try {
printL2();
} catch {
console.log(can't find l in printL2
)
}
在ECMAScript(JavaScript)裡,嚴謹/限制程度由高到低爲:const變數、let變數、var變數、全域變數。以前沒有const和let,現在通常會建議使用let而非var,因爲這樣會在執行時期(Runnint Time)檢查是否有邏輯錯誤。(如果你希望你的程式就算遇到非預期性錯誤,執行起來很怪,也不該報錯。那仍可以考慮使用var,這也是早期瀏覽器設計的考量。只是這樣的程式並不好除錯與維護)
對應表: printV1() <-> printL1() printV2() <-> printL2() printV3() <-> printL3()
最後附上完整程式碼,可以去玩玩看(到最下面還有一個可以想想看的):
function printG(){
g = 1
console.log(printG:
, g)
}
printG() // => printG: 1
console.log(Global G:
, g) // => Global G: 1
////////////////////////////////
function printV1(){
var v = 2
console.log(printV1:
, v)
}
printV1() // => pritnV1: 2
try{
console.log(v)// error
} catch {
console.log('not find v');
}
function printV2(){
console.log(printV2:
, v)
var v = 2
}
printV2() // => undefined
function printV3(){
if(true) {
var v = 2
}
console.log(printV3:
, v)
}
printV3() // => pritnV3: 2
//////////////////////////////////
function printL1(){
let l = 3;
console.log(printL1:
, l);
}
printL1() // => printL1: 3
try{
console.log(Global l:
, l); //error
} catch {
console.log(not find l
);
}
function printL3(){ if(true){ let l = 3 }
try {
console.log(printL2:
, l)
} catch {
console.log(can't find l in printL3
)
}
}
printL3() // => can't find l in printL2
function printL2() { console.log(l) let l = 3 }
try {
printL2();
} catch {
console.log(can't find l in printL2
)
}
那麼...對於可以在函式任意地方宣告的var變數,下面程式行爲又會如何?
var v1 = 9
function printV0(){
console.log(printV2:
, v1)
var v1 = 2
console.log(printV2:
, v1)
}
printV0()
https://lighthouse.alphacamp.co/courses/39/assignments/919/submissions/98590?comment_id=93893&question_id=2025