JavaScript 中的 null 和 undefined 有什么区别?它们各自的使用场景是什么?

5 阅读3分钟

JavaScript 中的 null 和 undefined 有什么区别?它们各自的使用场景是什么?

核心答案

undefined 表示"未定义",是变量声明后但未赋值时的默认值,代表系统级别的、意料之外的空值

null 表示"空值",是一个被显式赋予的值,代表程序级别的、意料之中的空值

特性undefinednull
含义未定义、缺失空、无
来源系统自动赋予程序员主动赋值
typeof"undefined""object" (历史bug)
转为数字NaN0

深入解析

1. 产生 undefined 的场景

// 1. 变量声明未赋值
let a;
console.log(a); // undefined

// 2. 访问对象不存在的属性
let obj = {};
console.log(obj.name); // undefined

// 3. 函数没有返回值
function fn() {}
console.log(fn()); // undefined

// 4. 函数参数未传递
function greet(name) {
  console.log(name); // undefined
}
greet();

// 5. 数组空位
let arr = [1, , 3];
console.log(arr[1]); // undefined

2. 使用 null 的场景

// 1. 显式表示"空"或"无"
let selectedUser = null; // 当前没有选中用户

// 2. 作为函数参数表示空值
document.getElementById('not-exist'); // 返回 null

// 3. 原型链的终点
Object.getPrototypeOf(Object.prototype); // null

// 4. 释放对象引用(帮助垃圾回收)
let bigData = { /* 大量数据 */ };
bigData = null; // 显式释放

3. 类型转换差异

// 转为布尔值 - 都是 false
Boolean(undefined); // false
Boolean(null);      // false

// 转为数字 - 差异明显
Number(undefined);  // NaN
Number(null);       // 0

// 这导致运算结果不同
undefined + 1;  // NaN
null + 1;       // 1

4. 相等性比较

// 宽松相等
null == undefined;   // true(特殊规则)
null == 0;           // false
undefined == 0;      // false

// 严格相等
null === undefined;  // false
null === null;       // true
undefined === undefined; // true

5. 常见误区

误区一:typeof null 返回 "object"

typeof null; // "object" — 这是 JS 诞生之初的 bug,至今未修复
// 正确判断 null 的方式
value === null

误区二:认为 undefined 和 null 可以随意互换

// JSON 序列化时行为不同
JSON.stringify({ a: undefined, b: null });
// '{"b":null}' — undefined 属性被忽略!

误区三:用 == null 检测两者

// 这是个技巧,可以同时检测 null 和 undefined
function isNullish(value) {
  return value == null; // 等同于 value === null || value === undefined
}

代码示例

默认参数处理

// undefined 会触发默认值,null 不会
function greet(name = 'Guest') {
  console.log(`Hello, ${name}!`);
}

greet();          // "Hello, Guest!"
greet(undefined); // "Hello, Guest!"
greet(null);      // "Hello, null!" — null 不触发默认值

解构赋值的默认值

const { a = 10, b = 20 } = { a: undefined, b: null };
console.log(a); // 10 — undefined 触发默认值
console.log(b); // null — null 不触发默认值

可选链与空值合并

const user = { profile: null };

// 可选链 - null 和 undefined 都会短路
user.profile?.name;  // undefined

// 空值合并 - 仅对 null/undefined 生效
const name = null ?? 'Anonymous';  // 'Anonymous'
const age = 0 ?? 18;               // 0(不是 18!)

// 对比 || 运算符
const name2 = null || 'Anonymous'; // 'Anonymous'
const age2 = 0 || 18;              // 18(falsy 值都会触发)

TypeScript 中的区别

// TypeScript 中可以明确区分
let a: string | undefined;  // 可能未赋值
let b: string | null;       // 可能为空

// strictNullChecks 开启后
interface User {
  name: string;
  nickname?: string;        // string | undefined
  deletedAt: Date | null;   // 显式可为空
}

面试技巧

面试官可能的追问方向

  1. 为什么 typeof null 是 "object"?

    • JS 最初版本中,值以 32 位存储,低 3 位表示类型
    • 对象的类型标志是 000,而 null 的机器码全是 0
    • 所以 null 被错误识别为对象
  2. 如何准确判断 null 和 undefined?

    value === null
    value === undefined
    // 或者
    value == null // 同时判断两者
    
  3. ES6+ 中处理空值的新特性?

    • 可选链 ?.
    • 空值合并 ??
    • 逻辑赋值 ??=
  4. 在 API 设计中如何选择使用 null 还是 undefined?

展示深度的方式

  • 提到 void 0 生成 undefined 的惯用法(用于压缩和防止 undefined 被重写)
  • 解释为什么 null 是 JavaScript 的"十亿美元错误"(来自 Null Reference 的发明者 Tony Hoare)
  • 讨论 TypeScript 的 strictNullChecks 如何增强类型安全

一句话总结

undefined 是系统给的"未定义",null 是程序员给的"空值";检测时用 === null=== undefined,同时检测用 == null;转数字时 undefined 变 NaN、null 变 0。