TypeScript - null 與 undefined 的差異

Hello, 有志者們!今天,我們將深入一個常讓初學者感到困惑的興奮主題:TypeScript 中 nullundefined 的差異。別擔心如果你覺得有點不知所措 – 我記得我第一次遇到這些概念時,我也曾經抓破頭!但到了這堂課的結束,你將會專業地區分這兩個特殊值。我們開始吧!

TypeScript - null vs. undefined

null 是什麼?

在 TypeScript(和 JavaScript)中,null 是一個特殊的值,代表故意沒有任何對象值。這就像在說,「嘿,這裡應該有東西,但現在,什麼都沒有。」

讓我們看一些例子來更好地理解這個概念:

let myPet: string | null = null;
console.log(myPet); // 輸出:null

// 代碼稍後...
myPet = "Fluffy";
console.log(myPet); // 輸出:Fluffy

在這個例子中,我們聲明了一個可以為 string 或 null 的變量 myPet。最初,我們將它設為 null,表示我們還沒有寵物。稍後,當我們有寵物時,我們將名字 "Fluffy" 賦值給 myPet

這裡有另一個例子:

function findUser(id: number): { name: string } | null {
// 想像我們正在搜索數據庫
if (id === 1) {
return { name: "Alice" };
} else {
return null;
}
}

let user = findUser(1);
console.log(user); // 輸出:{ name: "Alice" }

user = findUser(2);
console.log(user); // 輸出:null

在這種情況下,我們的 findUser 函數返回一個用戶對象或 null 如果沒有找到用戶。這是編程中常見的模式 - 使用 null 來表示搜索或操作沒有產生結果。

undefined 是什麼?

現在,讓我們來谈谈 undefined。這個特殊值代表一個已聲明但尚未賦值的變量。這就像一個空盒子 - 它存在,但還沒有東西。

這裡有一些例子來說明 undefined

let myName: string;
console.log(myName); // 輸出:undefined

// 代碼稍後...
myName = "John";
console.log(myName); // 輸出:John

function greet(name?: string) {
console.log(name);
}

greet(); // 輸出:undefined
greet("Alice"); // 輸出:Alice

在第一部分,我們聲明了 myName 但沒有賦值。TypeScript 自動給它 undefined 的值。稍後,我們賦值,它就不再是 undefined。

greet 函數中,我們使用了一個可選參數。如果我們在不提供參數的情況下調用函數,name 參數將會是 undefined

這裡有另一個你可能會遇到 undefined 的情況:

let person = {
name: "Bob",
age: 30
};

console.log(person.name); // 輸出:Bob
console.log(person.job); // 輸出:undefined

在這種情況下,person.jobundefined,因為我們從未為我們的 person 對象定義過 job 屬性。

Null 與 Undefined:關鍵差異

現在我們已經分別探討了 nullundefined,讓我們將它們並列比較,以更好地理解它們的差異。

方面 null undefined
含義 故意缺少任何對象值 變量已聲明但未賦值
類型 對象 Undefined
在 JSON 中 有效 無效
函數默認參數 不用作默認 用作可選參數的默認
相等性 null == undefined (true), null === undefined (false) undefined == null (true), undefined === null (false)

讓我們看一些代碼例子來說明這些差異:

// 類型檢查
console.log(typeof null);       // 輸出:"object"
console.log(typeof undefined);  // 輸出:"undefined"

// JSON 序列化
console.log(JSON.stringify({ a: null }));     // 輸出:{"a":null}
console.log(JSON.stringify({ a: undefined })); // 輸出:{}

// 函數默認參數
function sayHello(name: string = "World") {
console.log(`Hello, ${name}!`);
}

sayHello();        // 輸出:Hello, World!
sayHello(undefined); // 輸出:Hello, World!
sayHello(null);    // 輸出:Hello, null!

// 相等性
console.log(null == undefined);  // 輸出:true
console.log(null === undefined); // 輸出:false

實際上,在 nullundefined 之間的選擇通常取決於個人或團隊的偏好。然而,理解這些差異可以幫助你寫出更精確且無錯誤的代碼。

這裡有一個最後的例子來總結一切:

function processUser(user: { name: string, age?: number } | null | undefined) {
if (user === null) {
console.log("用戶顯式設為 null");
} else if (user === undefined) {
console.log("用戶未提供");
} else {
console.log(`處理用戶:${user.name}, 年齡:${user.age ?? "未知"}`);
}
}

processUser(null);                    // 輸出:用戶顯式設為 null
processUser(undefined);               // 輸出:用戶未提供
processUser({ name: "Alice" });       // 輸出:處理用戶:Alice, 年齡:未知
processUser({ name: "Bob", age: 30 }); // 輸出:處理用戶:Bob, 年齡:30

這個函數展示了我們如何在真實世界情況中區分 nullundefined 和有效的用戶對象。

這就是全部了!你剛剛學會了 TypeScript 中 nullundefined 的來龍去脈。記住,熟練來自練習,所以不要害怕在你自己的代碼中嘗試這些概念。快樂編程,願你的變量總是故意地為 null 或 undefined!

Credits: Image by storyset