JavaScript 数据类型全解析:从内存机制到上下文行为
✅ 核心结论
- 分类标准:JavaScript 数据类型分为基本数据类型(存放在栈,值不可变)和引用数据类型(存放在堆,通过地址引用)。
- 内存特征:基本类型是“值传递”,修改互不影响;引用类型是“址传递”,多个变量可共享并修改同一块内存数据。
- 动态特性:JS 是弱类型语言,数据会根据执行上下文(运算、方法调用等)自动进行类型转换或临时包装。
- 记忆口诀:“四基一空一未定,符号大数后加进;对象函数与数组,引用类型在堆里。”
🧠 关键概念
- 基本数据类型 (7种):
Number(含 NaN/Infinity)、String、Boolean、Undefined、Null。- ES6+ 新增:
Symbol(唯一标识)、BigInt(大整数)。
- 引用数据类型:
Object(基石),衍生出Array、Function、Date、RegExp等。 - 隐式类型转换:在字符串上下文(
+)、数值上下文(-、*、/)或布尔上下文(if判断)中,JS 会自动转换数据类型。 - 包装对象 (Wrapper Object):当基本类型调用属性或方法时,JS 会临时将其包装成对象,调用完后立即销毁。
📌 适用场景
- 唯一属性名:使用
Symbol定义对象属性,避免命名冲突。 - 高精度计算:处理超过 $2^{53}-1$ 的大整数时必须使用
BigInt。 - 精确类型判断:
- 基础判断用
typeof。 - 数组判断用
Array.isArray()。 - 全能判断用
Object.prototype.toString.call()。
- 基础判断用
- 复杂数据结构:利用引用类型的特性,通过
Object或Array组织结构化数据。
⚠️ 常见误区
typeof null:结果为"object",这是 JS 的历史遗留 Bug,不代表 null 是对象。- 引用共享陷阱:将一个对象赋值给新变量时,修改新变量的属性会同步影响原对象。
typeof局限性:无法区分数组、对象和 null,它们都会返回"object"。- 比较差异:基本类型比较的是“值”,引用类型比较的是“内存地址”。即使两个对象内容完全一样,
{} === {}也是false。
✅ 示例
1. 引用共享与基本类型区别
// 基本类型:值拷贝
let x = 10;
let y = x;
y = 20; // x 依然是 10
// 引用类型:地址共享
let obj1 = { val: 10 };
let obj2 = obj1;
obj2.val = 20; // obj1.val 变成了 20
2. 隐式转换上下文
"10" + 5; // "105" (字符串上下文)
"10" - 5; // 5 (数值上下文)
!! "hello"; // true (布尔上下文)
3. 精确类型判断
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(new Date()); // "[object Date]"