基本类型与对象类型
099 Primitives vs. Objects (Primitive vs. Reference Types) 笔记
一、核心问题引入:原始类型与对象的行为差异
1.1 原始类型的 “预期行为”(代码示例)
1 | // 1. 声明原始类型变量(数字) |
结论:原始类型复制后,修改原变量不会影响复制变量,符合直觉。
1.2 对象类型的 “意外行为”(代码示例)
1 | // 1. 声明对象类型变量 |
问题:为何修改friend会影响me?需从 “内存存储机制” 解释。
二、基础知识回顾:JS 数据类型分类
2.1 原始类型(Primitive Types,又称 “值类型”)
- 包含 7 种:
Number(数字)、String(字符串)、Boolean(布尔值)、Undefined(未定义)、Null(空值)、Symbol(唯一标识)、BigInt(大整数)。 - 特点:存储 “具体值”,占用内存小且固定。
2.2 引用类型(Reference Types,核心是对象)
- 包含:
Object(普通对象)、Array(数组,本质是特殊对象)、Function(函数,本质是可执行对象)、Date(日期对象)等。 - 特点:存储 “复杂结构”,占用内存大小不固定。
三、关键原理:JS 引擎的内存存储机制
3.1 内存分区:调用堆栈(Call Stack)与堆(Heap)
| 内存区域 | 存储内容 | 特点 |
|---|---|---|
| 调用堆栈 | 原始类型、函数执行上下文 | 速度快,内存大小有限,自动释放 |
| 堆 | 引用类型(对象) | 速度较慢,内存空间大,手动回收(GC) |
3.2 原始类型的内存存储流程(对应 1.1 示例)
-
声明
1
age = 30
时:
- 调用堆栈中分配一块内存(地址如
0001),存储值30; - 变量
age指向内存地址0001(而非直接指向值30)。
- 调用堆栈中分配一块内存(地址如
-
复制
1
oldAge = age
时:
oldAge直接指向age的内存地址0001,与age共享同一值。
-
修改
1
age = 31
时:
- 原始类型值不可变(无法直接修改
0001地址的值); - 新分配一块内存(地址如
0002),存储31; age转而指向0002,oldAge仍指向0001(值30)。
- 原始类型值不可变(无法直接修改
3.3 引用类型的内存存储流程(对应 1.2 示例)
-
声明
1
const me = {name: "Jonas", age: 30}
时:
- 堆中分配一块内存(地址如
D30F),存储对象的键值对; - 调用堆栈中分配一块内存(地址如
0003),存储堆地址D30F; - 变量
me指向调用堆栈的0003(间接指向堆中的对象)。
- 堆中分配一块内存(地址如
-
复制
1
const friend = me
时:
friend指向调用堆栈中与me相同的地址0003;- 二者通过
0003间接指向堆中同一对象(D30F),未创建新对象。
-
修改
1
friend.age = 27
时:
- 直接修改堆中
D30F地址的对象属性(age从30改为27); me和friend仍共享同一堆地址D30F,因此二者访问到的age均为27。
- 直接修改堆中
四、重要延伸:const声明的可变性差异
4.1 const与原始类型:完全不可变
1 | const num = 10; |
原因:const声明的原始类型变量,其指向的内存地址不可变,且原始类型值本身不可变,因此变量完全无法修改。
4.2 const与引用类型:引用不可变,属性可变
1 | const person = { name: "Alice", age: 25 }; |
原因:const仅禁止修改 “调用堆栈中的引用地址”(如person不能从指向0003改为指向0004),但不限制 “堆中对象属性的修改”。
五、实践影响与后续学习提示
5.1 常见坑点:“复制对象” 的本质
-
误区:
const newObj = oldObj不是 “复制对象”,而是 “复制引用”,二者指向同一对象。 -
示例(坑点):
1
2
3
4const user1 = { score: 80 };
const user2 = user1;
user2.score = 90;
console.log(user1.score); // 输出:90(意外修改了原对象)
5.2 后续学习方向
- 解决 “对象深复制” 问题:后续课程会讲解
Object.assign()、扩展运算符(...)、JSON.parse(JSON.stringify())等深复制方法,避免引用共享导致的意外修改。 - 关联核心概念:
- 原型继承(OOP 章节):对象的原型链依赖引用类型的内存机制;
- 事件循环(异步 JS 章节):堆中对象的回收时机与事件循环相关;
- DOM 操作(高级 DOM 章节):DOM 元素本质是引用类型,修改 DOM 属性的原理与对象一致。
六、总结:原始类型与引用类型核心差异表
| 对比维度 | 原始类型(值类型) | 引用类型(对象) |
|---|---|---|
| 存储位置 | 调用堆栈 | 堆(调用堆栈存引用地址) |
| 复制行为 | 复制值,修改原变量不影响副本 | 复制引用,修改副本影响原对象 |
const可变性 |
完全不可变(地址和值均不可改) | 引用不可变,对象属性可改 |
| 典型示例 | let a = 10、const str = "abc" |
const obj = {}、let arr = [] |
本文是原创文章,采用CC BY-NC-SA 4.0协议,完整转载请注明来自木鱼的鱼窝


