JavaScript面試題:var let const的差別
var
、let
、const
都是JS中常見的變數宣告方式,三者版本不同(let
跟const
是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
let
、const
具有區塊作用域,意思就是只能在{ }
內取用,在外面不能取用:
{
let d = 5
}
console.log(d)
//Uncaught ReferenceError: d is not defined
{
const e = 5
}
console.log(e)
//Uncaught ReferenceError: e is not defined
let
跟const
在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)
,接下來就是var
跟let
的差異。
- 複習event loop:JavaScript面試題:什麼是Event Loop?
執行時間點: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
由此可見let
跟const
比var
更為嚴謹,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)
}
最近在看宋慧喬演的黑暗榮耀,好好看哦!!韓國真的好會把社會議題拍成韓劇ㄟ
參考資料:
https://medium.com/randy-chen/let-%E5%92%8C-var-%E5%9C%A8-for%E8%BF%B4%E5%9C%88%E4%B8%AD%E7%9A%84%E7%B5%90%E6%9E%9C%E5%B7%AE%E7%95%B0-54f61cdb5f48
https://www.programfarmer.com/articles/javaScript/javascript-var-let-const-for-loop
https://totoroliu.medium.com/javascript-var-let-const-%E5%B7%AE%E7%95%B0-e3d930521230