JavaScript面試題:var let const的差別

Wendy Chang
Wendy Loops
Published in
7 min readJan 14, 2023

--

varletconst都是JS中常見的變數宣告方式,三者版本不同(letconst是ES6才有的),作用域範圍不同,也跟能不能重新賦值有關係;若能了解三者的差異,之後報錯就更容易除錯。

作用域(scope)不同

var

var具有函式作用域,在函式內宣告但在外部會無法使用:

function fn(){
var a = 5
}
console.log(a)
//Uncaught ReferenceError: a is not defined

var不具區塊作用域,意思就是var在其他{ }中宣告的話,外部仍可使用

{
var b = 4
}
console.log(b)
//4
if(b = 4){
var c = 3
}

console.log(c)
//3

let const

letconst具有區塊作用域,意思就是只能在{ }內取用,在外面不能取用:

{
let d = 5
}
console.log(d)
//Uncaught ReferenceError: d is not defined
{
const e = 5
}
console.log(e)
//Uncaught ReferenceError: e is not defined

letconst在function中被宣告,function同樣無法取用:

function fn(){
let f = 5
}

console.log(f)
//Uncaught ReferenceError: f is not defined
function fn(){
const g = 6
}

console.log(g)
//Uncaught ReferenceError: g is not defined

Hoisting提升不同

還不知道Hoisting的朋友快來看這篇:JavaScript面試考題:Hoisting是什麼?

var會hoisting

console.log(i);//undefined
var i = 5;
  • 這個undefined是純值(primitive value)
  • i已被賦值但尚未被宣告

let const不會hoisting

console.log(j);
let j = 6;

Uncaught ReferenceError: Cannot access ‘j’ before initialization

Uncaught ReferenceError: j is not defined

  • 不同版本瀏覽器會顯示不同的錯誤,但反正都是錯誤
console.log(k);
const k = 7;

Uncaught ReferenceError: Cannot access ‘k’ before initialization

Uncaught ReferenceError: k is not defined

可不可以重複宣告

var可以被重複宣告

var a = 5
console.log(a) //5
var a = 6
console.log(a) //6

let const不能被重複宣告

let a = 5
let a = 6
console.log(a)
//SyntaxError: Identifier 'a' has already been declared
const b = 5
const b = 6
console.log(b)
//SyntaxError: Identifier 'b' has already been declared

let const會比var更嚴謹。

let跟const的差異

let可以先不賦值,之後再賦值:

let i;
console.log(i); //undefined
i = 10;
console.log(i); //10

const一開始就一定要賦值,不可以之後才賦值,它會在一開始就立刻報錯:

const j;
//Uncaught SyntaxError: Missing initializer in const declaration

for迴圈中var與let的差異

先來看看在for loop中使用var會印出什麼?

for(var i=0; i<5; i++)
{
setTimeout(function(){
console.log(i)
}, 3000);
}

5
5
5
5
5

居然不是想像中的01234

setTimeOut()是一個非同步函式,JS讀到setTimeOut()後會丟給瀏覽器計時器計時,與此同時i仍在累加(var i = 0 , var i = 1, var i = 2, var i = 3, var i = 4, var i = 5),直到i < 5被跳出迴圈。

三秒過去後,再執行後方的回呼函式:console.log(i),接下來就是varlet的差異。

執行時間點:for迴圈跑完才印i

var沒有區塊作用域,而for loop也不是函式作用域,所以var在這時候會是一個全域變數(在全域讀得到i=5),而每一次var都會覆蓋掉上一次,所以最終就是var i = 5,印出5次都是5

let具有區塊作用域,每let一次,let都會建立新的執行環境,能夠紀錄多個i,在for loop中就會有多個i值,最後能夠印出01234

for(let i=0; i<5; i++)
{
setTimeout(function(){
console.log(i)
}, 3000);
}

0
1
2
3
4

由此可見letconstvar更為嚴謹,ES6之後鼓勵大家let const取代var

練習題

var data = [];

for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}

data[0]();
data[1]();
data[2]();

3
3
3

執行順序如下:
1. var i = 0
2. data[0] = 匿名函式
3. var i = 1
4. data[1] = 匿名函式
5. var i = 2
6. data[2] = 匿名函式
7. var i = 3 跳出迴圈
8. data[0]() 執行匿名函式 function(){ console.log(i) }
這時候 i = 3 ,所以會印出3
9. 同理data[1], data[2]也會印出3

for與var let const練習題

for(var i = 0 ; i < 3; i++){
console.log(i)
}
console.log(i)

for(var i; i < 6; i++){
console.log(i)
}
console.log(i)

for(let j =0 ; j < 3; j++){
console.log(j)
}
console.log(j)

for(const k = 0; k < 3; k++){
console.log(k)
}

最近在看宋慧喬演的黑暗榮耀,好好看哦!!韓國真的好會把社會議題拍成韓劇ㄟ

--

--

Wendy Chang
Wendy Loops

什麼都寫ㄉ前端工程師 / 影片剪輯師 / 自媒體經營者