TypeScript - null 与 undefined 的区别

你好,有抱负的程序开发者们!今天,我们将深入探讨一个经常让初学者感到困惑的激动人心的话题: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

在这个例子中,我们声明了一个可以是字符串或 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

在实践中,选择 null 还是 undefined 通常取决于个人或团队的偏好。然而,了解这些区别可以帮助你编写更精确且无错误的代码。

以下是一个最后的例子来概括所有内容:

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