null
与 undefined
的区别
本篇全文由DeepSeek生成, 觉得写得不错, 就发出来了
首先要明确的核心概念是:TypeScript 是 JavaScript 的超集 ,因此 null
和 undefined
的行为和区别首先源于 JavaScript,TypeScript 的类型系统在此基础上为我们提供了更强大的控制和安全性。
1. 含义与产生场景
这是理解两者区别最直观的方式。
undefined
(未定义)
- 含义 :表示一个变量已被声明,但尚未被赋值。它是所有未初始化变量的默认值。
- 常见产生场景 :
-
声明了变量但没有赋值。
typescriptlet a: number; console.log(a); // 输出: undefined
-
访问对象不存在的属性。
typescriptconst obj = { name: 'Alice' }; console.log(obj.age); // 输出: undefined
-
函数被调用时,未提供的参数。
typescriptfunction greet(name: string) { return `Hello ${name}`; } greet(); // TypeScript 会报错,但在 JS 运行时 name 参数是 undefined
-
函数没有显式返回任何值(即没有
return
语句或return;
),默认返回undefined
。typescriptfunction doNothing() {} console.log(doNothing()); // 输出: undefined
-
null
(空值)
- 含义 :表示一个**"空"的或 "不存在"的对象的引用。它是一个显式赋值的值**,用来表示"这里应该有值,但现在是空的"。
- 常见产生场景 :
-
由程序员主动显式地 赋给一个变量,以清空该变量或表示其无值。
typescriptlet user = { name: 'Bob' }; user = null; // 明确表示 user 不再指向任何对象
-
作为函数的参数,表示应该传入一个空值。
-
一些 DOM API 方法在找不到元素时会返回
null
。typescriptconst element = document.getElementById('non-existent-id'); console.log(element); // 输出: null
-
2. TypeScript 类型系统中的区别
TypeScript 有各自独立的类型:
undefined
类型只有一个值:undefined
。null
类型只有一个值:null
。
默认情况下,它们是所有其他类型的子类型。这意味着在 strictNullChecks
选项关闭 时(不推荐),你可以把 null
和 undefined
赋值给任意类型的变量(如 string
, number
)。
typescript
// 假设 strictNullChecks: false (旧版TS或宽松配置)
let title: string;
title = 'Hello'; // OK
title = null; // OK
title = undefined; // OK
let age: number = null; // OK
然而,最佳实践是始终开启 strictNullChecks
(在 tsconfig.json
中设置)。开启后:
null
和undefined
不能再赋值给其他类型。- 它们只能赋值给自身类型和
any
类型。 - 这能有效避免运行时"Cannot read property 'X' of null/undefined"这类常见错误。
typescript
// 假设 strictNullChecks: true (推荐配置)
let title: string;
title = 'Hello'; // OK
title = null; // ❌ 错误: Type 'null' is not assignable to type 'string'.
title = undefined; // ❌ 错误: Type 'undefined' is not assignable to type 'string'.
// 如果一个变量确实可能为 null 或 undefined,必须明确声明!
let maybeName: string | null = null;
maybeName = 'Alice'; // OK
maybeName = null; // OK
maybeName = undefined; // ❌ 错误: Type 'undefined' is not assignable to type 'string | null'.
3. 相等性检查 (==
vs ===
)
这是一个非常重要的行为差异。
-
非严格相等 (
==
) :null
和undefined
在非严格相等比较时被认为是相等的。typescriptconsole.log(null == undefined); // true
-
严格相等 (
===
) :null
和undefined
是不同类型的值,严格比较时不相等。typescriptconsole.log(null === undefined); // false
建议 :在 TypeScript 和现代 JavaScript 开发中,始终使用 ===
以避免隐式类型转换带来的意外行为。
4. JSON 序列化
在将数据转换为 JSON 字符串时,两者的行为也不同:
undefined
的属性会被完全忽略,不会出现在 JSON 字符串中。null
的属性会被保留 ,其值为null
。
typescript
const data = { name: 'Alice', age: undefined, address: null };
const jsonString = JSON.stringify(data);
console.log(jsonString); // 输出: '{"name":"Alice","address":null}'
// 注意 `age` 属性消失了
总结与对比表格
特性 | undefined |
null |
---|---|---|
含义 | 变量已声明但未赋值 | 表示一个空的对象引用(主动赋值) |
类型 | undefined |
null |
产生方式 | 由 JavaScript 引擎自动分配 | 由程序员显式分配 |
typeof 运算 |
"undefined" |
"object" (这是JS的历史遗留bug) |
== 比较 |
null == undefined 为 true |
undefined == null 为 true |
=== 比较 |
null === undefined 为 false |
undefined === null 为 false |
JSON 序列化 | 属性被忽略 | 属性值变为 null |
实践建议
-
开启
strictNullChecks
:这是避免空值错误的最重要手段。 -
使用联合类型 :如果一个值确实可能为空,明确使用
string | null
或string | undefined
甚至string | null | undefined
来声明其类型。 -
优先使用
undefined
:在很多场景下(如可选参数、可选属性),TypeScript 默认使用undefined
。保持一致性可以使代码更清晰。你可以将undefined
视为"系统级"的缺失,而null
视为"程序级"的空白赋值。 -
明确检查 :在使用一个可能为
null
或undefined
的值前,一定要进行检查。typescriptfunction doSomething(str: string | null) { if (str === null) { // 处理 null 的情况 return; } // 现在 TypeScript 知道这里的 str 一定是 string 类型 console.log(str.length); }
也可以使用可选链 (
?.)
和空值合并 (??
) 运算符 来简化操作:typescriptconst length = maybeName?.length ?? 0; // 如果 maybeName 为 null/undefined,则返回 0