🚀 JavaScript 基礎(第 03 週):每個開發者都應該了解的概念

「撰寫 JavaScript 程式碼是一回事,但了解幕後發生的事情才能讓你成為更好的開發者。」

當我剛開始學習 JavaScript 時,我知道如何宣告變數和撰寫函式。然而,我常常會問自己:

  • 為什麼有三種宣告變數的方法?
  • 到底什麼是提升(hoisting)?
  • JavaScript 是如何執行我的程式碼的?
  • 為什麼內層函式可以存取父函式的變數?
  • this 關鍵字到底指向什麼?
  • 為什麼開發者一直在談論撰寫乾淨的程式碼?

這週,我專注於理解這些 JavaScript 核心概念,而不只是死記語法。

在這篇文章中,我會以初學者友善的方式搭配範例與實務解釋來說明每個概念。


📚 涵蓋主題

  • 變數(varletconst
  • 提升(Hoisting)
  • 詞法作用域(Lexical Scope)
  • 執行環境(Execution Context)
  • 呼叫堆疊(Call Stack)
  • 閉包(Closures)
  • this 綁定
  • DRY 原則
  • KISS 原則

讓我們從頭開始。


📦 JavaScript 中的變數

什麼是變數?

變數是一個用來在記憶體中儲存資料的命名容器

與其重複撰寫相同的值,我們可以將它儲存在變數中,並在需要時重複使用。

例如,

let name = "Sai";

console.log(name);

Enter fullscreen mode Exit fullscreen mode

輸出

Sai

Enter fullscreen mode Exit fullscreen mode

在這裡,

  • let → 變數宣告關鍵字
  • name → 變數名稱
  • "Sai" → 儲存的值

為什麼需要變數?

想像撰寫以下程式碼:

console.log("Sai");
console.log("Sai");
console.log("Sai");

Enter fullscreen mode Exit fullscreen mode

如果值改變,就必須更新每一處。

使用變數後,

let name = "Sai";

console.log(name);
console.log(name);
console.log(name);

Enter fullscreen mode Exit fullscreen mode

現在只需修改一行,就能更新所有使用處。

變數可提升:

  • 可讀性
  • 可重用性
  • 可維護性

變數的類型

JavaScript 提供了三種宣告變數的方式。

  • var
  • let
  • const

雖然這三者都能建立變數,但它們的行為不同。


var

var 在 JavaScript 的第一個版本中就被引入。

特性:

  • 函式作用域
  • 可以重新宣告
  • 可以重新指派
  • 會被提升

範例

var city = "Hyderabad";

var city = "Bangalore";

console.log(city);

Enter fullscreen mode Exit fullscreen mode

輸出

Bangalore

Enter fullscreen mode Exit fullscreen mode

因為 var 允許重新宣告,它可能意外覆寫現有值。


let

let 在 ES6 中被引入。

特性

  • 區塊作用域
  • 無法重新宣告
  • 可以重新指派

範例

let age = 20;

age = 21;

console.log(age);

Enter fullscreen mode Exit fullscreen mode

輸出

21

Enter fullscreen mode Exit fullscreen mode


const

當變數不應被重新指派時,請使用 const

特性

  • 區塊作用域
  • 無法重新宣告
  • 無法重新指派
const PI = 3.14;

console.log(PI);

Enter fullscreen mode Exit fullscreen mode

輸出

3.14

Enter fullscreen mode Exit fullscreen mode


📈 提升(Hoisting)

什麼是提升?

提升是 JavaScript 在執行程式碼前先處理宣告的行為。

這並不代表程式碼在實體上移動。相反地,在記憶體建立階段,JavaScript 會在執行開始前先準備變數與函式。

範例

console.log(language);

var language = "JavaScript";

Enter fullscreen mode Exit fullscreen mode

輸出

undefined

Enter fullscreen mode Exit fullscreen mode

在內部,JavaScript 會將它視為:

var language;

console.log(language);

language = "JavaScript";

Enter fullscreen mode Exit fullscreen mode

使用 letconst 宣告的變數也會被提升,但它們會留在暫時性死區(TDZ)中,直到被初始化。


🌍 詞法作用域

作用域決定變數可以在哪裡被存取。

詞法作用域指的是,內層函式可以存取外層函式中宣告的變數,這是由於它撰寫的位置所決定的。

範例

function outer(){

    let message="Hello";

    function inner(){

        console.log(message);

    }

    inner();

}

outer();

Enter fullscreen mode Exit fullscreen mode

輸出

Hello

Enter fullscreen mode Exit fullscreen mode

JavaScript 會先在 inner() 內搜尋。如果找不到變數,它會繼續在外層函式中尋找。

這個搜尋過程稱為作用域鏈(Scope Chain)


⚙️ 執行環境

在 JavaScript 執行任何程式碼之前,會先建立一個執行環境

可以把它想像成 JavaScript 的工作區。

它會儲存:

  • 變數
  • 函式
  • 作用域
  • this 的值

每個執行環境都有兩個階段。

記憶體建立階段

在此階段,

  • 變數會被配置記憶體。
  • var 變數會被初始化為 undefined
  • 函式宣告會被儲存。

執行階段

在此階段,

  • 變數會取得值。
  • 陳述式會逐一執行。
  • 函式呼叫會建立新的執行環境。

📚 呼叫堆疊

呼叫堆疊會追蹤函式的執行。

它遵循後進先出(LIFO)原則。

範例

function first(){

    second();

}

function second(){

    console.log("Inside Second");

}

first();

Enter fullscreen mode Exit fullscreen mode

輸出

Inside Second

Enter fullscreen mode Exit fullscreen mode

執行流程

first()



second()



console.log()



Return



Return

Enter fullscreen mode Exit fullscreen mode


🔒 閉包

JavaScript 最強大的特性之一就是閉包。

當內層函式即使在外層函式執行完畢後,仍然記得外層函式的變數時,就會建立閉包。

範例

function counter(){

    let count = 0;

    return function(){

        count++;

        console.log(count);

    }

}

const increment = counter();

increment();

increment();

increment();

Enter fullscreen mode Exit fullscreen mode

輸出

1
2
3

Enter fullscreen mode Exit fullscreen mode

閉包通常用於:

  • 計數器
  • 資料隱私
  • 事件處理器
  • 模組模式

🎯 理解 this

this 關鍵字指的是呼叫函式的物件。

它的值取決於函式如何被呼叫

隱式綁定

const user = {

    name:"Sai",

    greet(){

        console.log(this.name);

    }

}

user.greet();

Enter fullscreen mode Exit fullscreen mode

輸出

Sai

Enter fullscreen mode Exit fullscreen mode


顯式綁定

JavaScript 提供了 call()apply()bind() 來明確決定 this 應該指向哪個物件。

function greet(){

    console.log(this.name);

}

const user={

    name:"Sai"

};

greet.call(user);

Enter fullscreen mode Exit fullscreen mode

輸出

Sai

Enter fullscreen mode Exit fullscreen mode


new 綁定

function Student(name){

    this.name=name;

}

const s1=new Student("Sai");

console.log(s1.name);

Enter fullscreen mode Exit fullscreen mode

輸出

Sai

Enter fullscreen mode Exit fullscreen mode


箭頭函式

箭頭函式沒有自己的 this

相反地,它們會從周圍的作用域繼承 this


✨ DRY 原則

DRY 代表

Don't Repeat Yourself(不要重複自己)

與其重複撰寫程式碼,

console.log("Welcome Sai");

console.log("Welcome Rahul");

Enter fullscreen mode Exit fullscreen mode

不如撰寫

function greet(name){

    console.log(`Welcome ${name}`);

}

greet("Sai");

greet("Rahul");

Enter fullscreen mode Exit fullscreen mode

優點

  • 可重用程式碼
  • 易於維護
  • 減少重複

💡 KISS 原則

KISS 代表

Keep It Simple, Stupid(保持簡單)

簡單的程式碼比複雜的程式碼更容易理解。

與其撰寫

function isEven(num){

    if(num%2===0){

        return true;

    }

    else{

        return false;

    }

}

Enter fullscreen mode Exit fullscreen mode

不如撰寫

function isEven(num){

    return num%2===0;

}

Enter fullscreen mode Exit fullscreen mode

簡單的程式碼:

  • 易於除錯
  • 易於維護
  • 易於理解

🎯 重點摘要

完成這週的學習後,我了解到:

  • 變數用來儲存資料。
  • 提升發生在記憶體建立階段。
  • 詞法作用域決定變數在哪裡可以被存取。
  • 執行環境提供程式碼執行的環境。
  • 呼叫堆疊管理函式的執行。
  • 閉包會在函式結束後保留變數。
  • this 的值取決於函式如何被呼叫。
  • 遵循 DRY 與 KISS 原則有助於撰寫乾淨且易維護的程式碼。

📝 結論

學習 JavaScript 不只是撰寫程式碼,更是了解語言在幕後如何運作。執行環境、作用域、閉包和 this 綁定等概念解釋了為什麼我們的程式碼會以這種方式運作。將這些基礎知識與 DRY 和 KISS 等乾淨程式碼原則結合,我們就能撰寫不僅正確,而且易讀、易維護且易擴展的程式碼。