JavaScript有7种原始类型和1种引用类型,typeof可判原始类型但null返回'object'、函数返回'function';Object.prototype.toString.call能精确识别所有类型;隐式转换易出错,推荐用===和显式转换。

JavaScript 有 7 种原始类型(string、number、boolean、null、undefined、symbol、bigint)和 1 种引用类型(object,含 Array、Function、Date、RegExp、Map、Set 等),但判断和转换时容易踩坑——比如 typeof null === 'object',或 [] == false 为 true。
用 typeof 判断原始类型,但注意 null 和函数的例外
typeof 是最常用的类型检测操作符,对原始类型基本可靠,但有两个经典反直觉点:
-
typeof null返回'object'(历史遗留 bug,ECMAScript 从未修复) -
typeof function() {}返回'function'(虽然函数在 JS 中是对象,但typeof单独给了它一个分类) - ES2020 起,
typeof 123n正确返回'bigint';但旧环境需用Object.prototype.toString.call(123n) === '[object BigInt]'
console.log(typeof 'hello'); // 'string'
console.log(typeof 42); // 'number'
console.log(typeof true); // 'boolean'
console.log(typeof undefined); // 'undefined'
console.log(typeof null); // 'object' ← 注意!
console.log(typeof Symbol()); // 'symbol'
console.log(typeof 123n); // 'bigint'
console.log(typeof []); // 'object'
console.log(typeof function(){}); // 'function'
用 Object.prototype.toString.call() 精确识别所有内置对象类型
这是唯一能稳定区分 Array、Date、RegExp、Map 等类型的通用方法,因为每个内置构造器都在内部设置了 [[Class]] 标签(现由 Symbol.toStringTag 控制):
- 返回格式统一为
'[object Xxx]',例如'[object Array]' - 对原始值也有效:
Object.prototype.toString.call(123)→'[object Number]' - 不依赖实例的
constructor或__proto__,更健壮
console.log(Object.prototype.toString.call([])); // '[object Array]' console.log(Object.prototype.toString.call(new Date())); // '[object Date]' console.log(Object.prototype.toString.call(/abc/)); // '[object RegExp]' console.log(Object.prototype.toString.call(new Map())); // '[object Map]' console.log(Object.prototype.toString.call(null)); // '[object Null]' console.log(Object.prototype.toString.call(undefined)); // '[object Undefined]'
隐式转换常发生在 ==、+、! 等操作中,规则复杂且易出错
JS 在比较或运算前会按抽象操作(如 ToNumber、ToString、ToBoolean)自动转换类型。这些规则不是线性的,而是分场景定义的:
立即学习“Java免费学习笔记(深入)”;
-
==触发「抽象相等比较算法」:0 == false、'' == false、[] == false都为true,但[0] == false也是true -
+遇到字符串就转字符串拼接:1 + '2'→'12';但1 + []→'1'(因为[]转空字符串) -
!先执行ToBoolean:只有false、0、-0、0n、''、null、undefined、NaN为 falsy
console.log(0 == false); // true
console.log([] == false); // true
console.log([0] == false); // true ← 容易误判
console.log('1' + 2); // '12'
console.log(1 + []); // '1'
console.log(![]); // false(空数组是 truthy)
显式转换推荐用字面量方式或构造函数,避免 new 创建包装对象
手动转换应优先使用简洁、无副作用的方式。避免用 new String()、new Number() 等,它们返回的是对象而非原始值,可能引发意料外的 typeof 结果:
- 转字符串:
String(x)或x + ''(不推荐new String(x)) - 转数字:
Number(x)(严格)、parseInt(x, 10)(截断)、parseFloat(x)(浮点);+前缀(如+x)简洁但对空格和null敏感 - 转布尔:
Boolean(x)或!!x;不要用!x两次以外的方式模拟 -
Array.from()或展开语法[...x]比Array.prototype.slice.call(x)更现代安全
console.log(typeof new String('a')); // 'object' ← 错误用法
console.log(typeof String('a')); // 'string' ← 正确
console.log(Number(' 42 ')); // 42
console.log(Number(null)); // 0 ← 注意!
console.log(Number(undefined)); // NaN
console.log(!![]); // true
console.log(Boolean({})); // true
类型判断真正难的不是记住 API,而是理解「何时该用 typeof,何时必须用 toString.call,以及为什么 == 在多数情况下应该被 === 替代」——尤其当数据来自 API、表单或 localStorage 时,原始值和包装对象、空数组和空对象、0 和 '0' 的边界极易混淆。











