Skip to content

Instantly share code, notes, and snippets.

@lagagain
Last active February 7, 2021 22:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lagagain/2f7211b14f373a037b4d17537eb1cad5 to your computer and use it in GitHub Desktop.
Save lagagain/2f7211b14f373a037b4d17537eb1cad5 to your computer and use it in GitHub Desktop.
var/let/global 變數差異

無關鍵字賦值、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()

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 v1 = 9
function printV0(){
console.log(`printV2:`, v1)
var v1 = 2
console.log(`printV2:`, v1)
}
printV0()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment