先记住这个答案
两者都表示「没有值」,但来源和意图不同。undefined 是语言自动产生的:变量声明了没赋值、函数参数没传、访问不存在的属性、函数没有 return,拿到的都是 undefined。null 是开发者主动写的,表示「这里应该是个对象,但现在是空的」。表现上的差别主要有四个:typeof null 是 'object' 而 typeof undefined 是 'undefined';null == undefined 为 true 但 === 为 false;转数字时 null 是 0、undefined 是 NaN;默认参数只在值是 undefined 时才生效。
undefined常表示未赋值typeof null是 object- 宽松相等时二者相等
- 默认参数只在值为
undefined时生效
把两者放进同一组操作里对比
面试时光背概念不够,最好能说出它们在具体操作里的不同结果。
function greet(name = '游客') {
return name
}
console.log(greet(undefined), greet(null)) // 只有 undefined 触发默认值
console.log(null == undefined, null === undefined)
console.log(Number(undefined), Number(null))
console.log(JSON.stringify({ a: undefined, b: null }))
console.log(null ?? '空', undefined ?? '空')查看输出与解释
游客 null
true false
NaN 0
{"b":null}
空 空第一行最容易踩坑。接口返回 { name: null } 时,解构 const { name = '游客' } = data 拿到的还是 null,拼进模板字符串里就成了「你好,null」。第三行说明 null + 1 是 1,undefined + 1 是 NaN,统计数据时遇到缺失值要特别小心。第四行说明 undefined 字段序列化时会被丢掉,null 会保留,这一点在提交接口时有实际用处。
项目里怎么选
一个简单的约定:自己主动表示「空」时用 null,把 undefined 留给「不存在、没传」这种语言自己产生的状态。这样看到 null 就知道是有人故意清空的,看到 undefined 就知道是没初始化或者字段根本不存在。
- 提交表单时用
null表示清空 - 编辑资料页里,用户把生日清空了。如果前端把字段设成
undefined,JSON.stringify会把它丢掉,后端收到的请求里没有这个字段,会理解成「不修改」。要让后端清空,必须显式传null。反过来,不想提交的字段设成undefined,正好能省掉手动删除。 - 判空时两个一起处理
- 大多数业务判断并不关心是哪一种空。
value == null这一个表达式就能同时匹配null和undefined,是少数推荐使用==的场合。更常见的写法是value ?? 默认值和obj?.a?.b,它们也同时把两者当成空,但不会像||那样把0和空字符串也当成空。
容易答错的地方
- 以为
null是一种对象 typeof null === 'object'只是早期实现留下的问题,null本身是原始值,不能读属性,读了会抛TypeError。- 以为给参数传
null也能用上默认值 - 默认参数和解构默认值只在值严格等于
undefined时触发。后端字段可能返回null的话,要用??兜底,比如const name = data.name ?? '游客'。 - 以为
undefined是关键字 undefined其实是全局对象上一个只读属性,不是保留字。在函数里let undefined = 1是合法的,会把它遮住。这也是很多老库用void 0来拿真正undefined的原因。
面试官还会怎么问?
null >= 0 为什么是 true,null == 0 却是 false?
大小比较会把 null 转成数字 0,所以 null >= 0 成立。但 == 对 null 有专门规则:null 只和 null、undefined 相等,不做数字转换,所以 null == 0 是 false。
删除一个对象属性,用 delete 还是赋值 undefined?
delete obj.a 之后属性真的没了,'a' in obj 是 false。赋值 undefined 之后属性还在,'a' in obj 是 true,Object.keys 也能列出来。需要区分「没有这个字段」和「字段为空」时,这个差别很关键。
TypeScript 里 undefined 和 null 怎么区分?
开启 strictNullChecks 后,它们是两种独立的类型。可选属性 name?: string 的类型是 string | undefined,不包含 null。后端可能返回 null 的字段要显式写成 string | null,否则类型和实际数据对不上。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。