Skip to content

存储位置:栈 vs 堆

原始数据类型存储在栈中,引用数据类型存储在堆中

分类举例存储位置(概念上)实际说明
原始类型number, string, boolean, undefined, null, symbol, bigintJS 引擎会把小、固定大小的原始值直接存在栈中,访问速度快。
引用类型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保持原状直至被回收

**引用类型 :**可修改原堆内存内容