魯斯前端布魯斯前端

文章中英模式

布魯斯前端JS面試題目 - JavaScript 作用域

解析 JavaScript 中的作用域機制、變數傳遞方式,以及立即執行函式(IIFE)的應用。掌握塊級作用域、函數作用域、經典 for 迴圈問題與解決方案。

影片縮圖

懶得看文章?那就來看影片吧

作用域是什麼?

作用域就像是一個變數的「活動範圍」,決定了變數在哪裡可以被使用。

三種作用域

  1. 1.
    塊級作用域:用 {} 包起來的區域
  2. 2.
    函數作用域:函數內部的區域
  3. 3.
    全域作用域:最外層的區域
// 塊級作用域
{
  let x = 1;  // 只能在這個大括號內使用
}
console.log(x); // 錯誤!x 不存在

// 函數作用域
function test() {
  var y = 2;  // 只能在這個函數內使用
}
console.log(y); // 錯誤!y 不存在

// 全域作用域
let z = 3;  // 到處都可以使用

變數傳遞的兩種方式

1. 傳值(基本型別)

  • 複製一份新的值
  • 修改新變數不會影響原變數

2. 傳參考(物件型別)

  • 複製的是「地址」
  • 修改新變數會影響原變數
// 傳值
let a = 1;
let b = a;  // 複製一份 1 給 b
b = 2;      // 修改 b 不會影響 a
console.log(a); // 還是 1

// 傳參考
let obj1 = { x: 1 };
let obj2 = obj1;  // 複製的是地址
obj2.x = 2;       // 修改 obj2 會影響 obj1
console.log(obj1.x); // 變成 2 了!

IIFE 是什麼?

IIFE(立即執行函式)就是一個馬上執行的函式,常用來:

  • 保護變數不被外面使用
  • 解決 for 迴圈的問題
// 基本用法
(function() {
  let secret = '不能說的秘密';
  console.log(secret); // 可以印出
})();
console.log(secret); // 錯誤!外面看不到

🔥 常見面試題目

(一) let var 差在哪?

解答:主要差異有:

  • let 一定要先宣告才能用,var 可以先用後宣告 (hoisting提升,用let可以及時發現bug)
  • let 在宣告前使用會直接報錯,讓你知道寫錯了
  • let 不會變成全域變數(不會掛在 window 上)

(二)經典的 for 迴圈面試題 - 以下輸出為何?

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

解答:會是 3, 3, 3

for (var i = 0; i < 3; i++) {
   setTimeout(() => console.log(i), 1000);
}
// 輸出:3, 3, 3

為什麼會這樣?

var 沒有塊級作用域

setTimeout 執行時,迴圈已經跑完了

此時 i 的值已經是 3

所以三個 setTimeout 都印出 3

解決方式

1. 使用 IIFE 的解法
for (var i = 0; i < 3; i++) {
   (function(j) {
     setTimeout(() => console.log(j), 1000);
   })(i);
}
// 輸出:0, 1, 2
為什麼這樣可以?

IIFE 創造了一個新的作用域

每次迴圈都把當下的 i 值傳進去

每個 setTimeout 都有自己的 j

所以可以正確印出 0, 1, 2

2. 使用 let 的解法(最推薦)
for (let i = 0; i < 3; i++) {
   setTimeout(() => console.log(i), 1000);
}
// 輸出:0, 1, 2
為什麼這樣可以?

let 有塊級作用域

每次迴圈都會創建一個新的 i

每個 setTimeout 都記住自己那次的 i

所以可以正確印出 0, 1, 2

(三)為什麼要用 IIFE?

解答:IIFE 創造了一個新的作用域,可以:

  • 保護變數不被外面修改
  • 讓程式碼更安全、更模組化