JavaScript typeof, null, 和 undefined
JavaScripttypeof,null, 和undefined深度解析
这三个概念是 JavaScript 类型系统的基石,也是面试和实际开发中最容易混淆的地方。特别是typeof null的“历史遗留问题”,是理解 JS 类型系统的关键。
1.undefined:未定义的值
含义
undefined表示**“变量已声明,但尚未赋值”**。它代表“缺失的值”。
何时出现?
- 变量声明但未赋值:
leta;console.log(a);// undefined - 函数没有返回值:
functionnoReturn(){}console.log(noReturn());// undefined - 访问对象不存在的属性:
constobj={name:"Alice"};console.log(obj.age);// undefined - 函数参数未传递:
functiongreet(name){console.log(name);}greet();// undefined
特性
undefined是全局对象的属性(但在严格模式下不可重新赋值)。typeof undefined返回"undefined"。- 最佳实践:检查变量是否存在时,推荐使用
=== undefined或== null(后者同时匹配 null)。
2.null:空对象指针
含义
null表示**“有意为空”或“没有对象”。它是一个对象类型的空值**。
何时出现?
- 手动赋值:
letuser=null;// 表示用户当前未登录或数据为空 - 函数返回“无结果”:
functionfindUser(id){// 如果没找到,返回 null 而不是 undefinedreturnnull;}
特性
typeof null返回"object"(这是 JS 的历史 Bug,详见下文)。null是原始值(Primitive),但在类型判断上被归类为对象。- 最佳实践:当你想明确表示“这里应该有个对象,但现在没有”时,使用
null。
3.typeof运算符
作用
typeof用于返回操作数的数据类型字符串。
语法
typeofoperand// 或typeof(operand)返回值对照表
| 值 | typeof返回结果 | 说明 |
|---|---|---|
数字 (123) | "number" | 包括整数和浮点数 |
字符串 ("hello") | "string" | |
布尔值 (true) | "boolean" | |
undefined | "undefined" | |
null | "object" | 历史遗留 Bug |
对象 ({}) | "object" | |
数组 ([]) | "object" | 注意:数组也是对象 |
函数 (function(){}) | "function" | 特例 |
| Symbol | "symbol" | ES6 新增 |
| BigInt | "bigint" | ES2020 新增 |
| 未声明的变量 | "undefined" | 不会报错 |
关键示例
console.log(typeof42);// "number"console.log(typeof"Hello");// "string"console.log(typeoftrue);// "boolean"console.log(typeofundefined);// "undefined"console.log(typeofnull);// "object" <-- 著名的 Bugconsole.log(typeof{});// "object"console.log(typeof[]);// "object" <-- 数组也是对象console.log(typeoffunction(){});// "function"console.log(typeofSymbol('id'));// "symbol"console.log(typeof10n);// "bigint"// 未声明的变量console.log(typeofnotExist);// "undefined" (不会抛出 ReferenceError)4. 核心难点:为什么typeof null是"object"?
历史原因
在 JavaScript 的最初版本(1995年)中,类型信息存储在值的底层表示中。
- 值的底层是一个 32 位整数。
- 类型标签(Type Tag)存储在低 3 位。
000被用来表示Object类型。null在底层表示为全 0 的机器码(0x00000000)。- 因此,当
typeof检查null时,它看到低 3 位是000,误以为它是一个对象。
为什么不能修复?
由于typeof null === "object"已经被广泛使用在数百万行代码中,如果现在修改它,会导致大量现有代码崩溃。因此,ECMAScript 委员会决定保留这个 Bug以保持向后兼容。
如何正确判断null?
由于typeof无法区分null和对象,必须使用严格相等:
constval=null;// ❌ 错误:无法区分 null 和对象if(typeofval==="object"){// 这里会进入,但 val 可能是 null 也可能是 {}}// ✅ 正确:显式检查 nullif(val===null){console.log("这是 null");}// ✅ 或者使用 Object.prototype.toString (最严谨)if(Object.prototype.toString.call(val)==="[object Null]"){console.log("这是 null");}5.nullvsundefined:区别与使用场景
| 特性 | undefined | null |
|---|---|---|
| 含义 | 未定义、缺失、未初始化 | 有意为空、空对象指针 |
| 来源 | 引擎自动赋值 | 开发者手动赋值 |
| 类型 | undefined | object(typeof 结果) |
| 相等性 | undefined == null为true | undefined === null为false |
| 使用场景 | 变量声明未赋值、函数无返回值 | 清空对象引用、表示“无数据” |
代码对比
// 场景 1:变量初始化leta;// 自动为 undefinedletb=null;// 手动设为 null// 场景 2:函数返回functiongetAge(){// 如果没算出年龄,返回 undefined (默认)}functiongetUser(id){// 如果用户不存在,返回 null (明确表示“查无此人”)returnnull;}// 场景 3:对象属性constuser={};console.log(user.name);// undefined (属性不存在)user.name=null;// 属性存在,但值为空console.log(user.name);// null6. 实用技巧与最佳实践
技巧 1:使用== null同时检查null和undefined
在 JavaScript 中,null == undefined返回true,而null === undefined返回false。
利用这个特性,可以简洁地检查“值是否为空”:
functionprocessValue(val){// 如果 val 是 null 或 undefined,都视为无效if(val==null){console.log("值无效");return;}console.log("值有效:",val);}processValue(undefined);// 值无效processValue(null);// 值无效processValue(0);// 值有效: 0processValue("");// 值有效: ""processValue(false);// 值有效: false注意:这只会匹配 null 和 undefined,不会匹配 0、空字符串或 false。
技巧 2:使用??(空值合并运算符)
ES2020 引入的??运算符,专门用于处理null和undefined。
constname=null;constdisplayName=name??"默认用户";// 输出 "默认用户"constcount=0;constdisplayCount=count??10;// 输出 0 (因为 0 不是 null/undefined)对比||运算符:0 || 10会返回10,因为0是假值。??更精准。
技巧 3:判断是否为对象(排除 null)
由于typeof null是"object",判断对象时需要排除 null:
functionisObject(val){returnval!==null&&typeofval==="object";}console.log(isObject({}));// trueconsole.log(isObject([]));// trueconsole.log(isObject(null));// falseconsole.log(isObject(123));// false7. 总结
undefined:系统自动赋值,表示“未定义”。typeof返回"undefined"。null:手动赋值,表示“空对象”。typeof返回"object"(历史 Bug)。typeof:- 是判断类型的首选工具。
- 对
null的判断失效,需配合=== null。 - 对数组返回
"object",需配合Array.isArray()。
- 判断空值:
- 严格区分:
val === null或val === undefined。 - 同时检查:
val == null或使用val ?? default。
- 严格区分:
