类型概览与判定
数据类型如何分类?
- 原始值 (primitive):
undefined、null、boolean、number、string、symbol、bigint, 值时操作, 无自有属性; - 引用值 (reference):
object, 包含Array、Function、Date、RegExp等, 按引用操作; - 存储差异与复制、传参行为见 原始值与引用值;
typeof 能判断出什么?
| 检测对象 | 返回值 |
|---|---|
undefined | "undefined" |
| Boolean | "boolean" |
| string | "string" |
| number | "number" |
| symbol | "symbol" |
| bigint | "bigint" |
| function | "function" |
object 或 null | "object" |
typeof null; // "object"; 历史遗留问题
typeof NaN; // "number"; NaN 属于 number 类型
typeof undeclaredVar; // "undefined"; 未声明变量也不报错
- 局限: 无法细分引用类型, 且把
null误判为object;
instanceof 如何判断引用类型?
- 机制: 沿
[[Prototype]]链查找构造函数的prototype, 详见 原型与原型链; - 原始值: 对原始值判断恒为
false; - object 判断: 任意引用值
instanceof Object恒为true;
person instanceof Object; // true
colors instanceof Array; // true
pattern instanceof RegExp; // true
判断类型的方法各有什么优劣?
| 方法 | 优点 | 缺点 |
|---|---|---|
typeof | 简单, 可判断原始类型 | 无法区分引用类型, null 判为 object |
instanceof | 可判断引用类型的继承关系 | 不能判断原始类型, 跨 realm 失效 |
constructor | 可检查除 null/undefined 的类型 | 跨 realm 失效, constructor 可被改写 |
Object.prototype.toString.call | 可覆盖所有内置类型 | 旧环境兼容性差 |
const str = "Hello";
typeof str; // "string"
Object.prototype.toString.call(str); // "[object String]"
- 组合口径: 原始类型用
typeof, 引用类型用Object.prototype.toString.call, 需要判断继承关系时用instanceof;
如何判断空对象与空值?
- 空对象:
Object.keys(obj).length === 0, 或for...in加hasOwnProperty过滤原型属性, 或JSON.stringify(obj) === "{}"; - 空值: 用宽松相等一次判掉
null与undefined;
if (value == null) {
// 同时覆盖 null 与 undefined
}