主题
存储位置:栈 vs 堆
原始数据类型存储在栈中,引用数据类型存储在堆中
分类 | 举例 | 存储位置(概念上) | 实际说明 |
---|---|---|---|
原始类型 | number , string , boolean , undefined , null , symbol , bigint | 栈 | JS 引擎会把小、固定大小的原始值直接存在栈中,访问速度快。 |
引用类型 | object , array , function , Date , Map , ... | 堆 | 在栈中保存一个指针(引用地址),指向堆中的实际对象内容。 |
引用数据类型在栈中存储了堆中的起始地址,当寻找引用值时,会首先在栈中获得引用的地址,取得地址后,再根据地址从堆中获得引用数据的真实内容。
传值 vs 传引用
JavaScript 所有传参都是按值传递
对于引用类型,传递的值是引用在堆中的地址
也就是说:
- 基本类型:传的是“值本身”;
- 引用类型:传的是“对象引用的地址值”,不是对象本身。
举例
js
let a = 10
let b = a
b = 20
console.log(a) // 10,不受影响
基本类型是值的复制,相当于在栈中新创建了一个相同的新值
js
let obj1 = { name: 'xxx' }
let obj2 = obj1
obj2.name = 'yyy'
console.log(obj1.name) // yyy
对象传递的是引用的地址,这两个变量指向同一个堆中的对象
js
let obj1 = { name: 'xxx' }
function change(o) {
o = { name: 'yyy' }
}
change(obj1)
console.log(obj1.name) // xxx
函数参数拿到的是“obj1引用在堆中的地址”,它可以通过引用修改对象内部属性,但不能让外部变量重新指向别的对象
类型赋值
不可变性原则: 原始类型的值一旦创建,就永远不可以被修改,任何看似修改的操作,实际都是创建新值
js
let a = 1; // 阶段1:栈内存创建值1,变量a指向它
a = 2; // 阶段2:栈内存创建新值2,变量a重定向到新地址
- **不是覆盖:**不会修改原栈内存位置的内容
- **不是引用更新:**而是创建全新的独立值
- **不是原地修改:**原始值1保持原状直至被回收
**引用类型 :**可修改原堆内存内容