计算机内存中的栈和堆 一、堆栈的定义程序运行时内存会划分出不同区域其中最重要的两块就是栈Stack和堆Heap。1. 栈Stack结构一种线性的、后进先出LIFO的数据结构。管理方式由操作系统或 JavaScript 引擎自动分配和释放无需开发者手动干预。比如函数调用时局部变量入栈函数执行完整块栈帧直接弹出内存瞬间回收。特点速度快直接通过移动栈指针来分配。空间相对较小连续存储。存储大小固定、生命周期可预知的数据。2. 堆Heap结构更像一个杂乱但自由的大仓库存储区域不一定连续通过指针引用。管理方式动态分配。何时分配、何时释放并不严格跟随函数进出而是由垃圾回收器GC通过算法判断对象是否还被使用来决定回收时机。特点速度较慢涉及内存查找与 GC。空间大适合存放大小不定或需要长期存在的数据。打个比方栈像便捷的随身口袋放快取快但容量小堆像家里的储物间空间大但找东西及收拾要花时间。二、JavaScript 的数据类型JavaScript 的值分为两大阵营原始类型Primitiveundefinednullbooleannumberbigintstringsymbol它们的特点不可变大小相对固定除了某些长字符串但引擎有优化。对象类型Reference / ObjectObject、Array、Function、Date、RegExp、Map、Set等。特点可变结构复杂大小动态增减。三、存储地方栈与堆的“分工”1. 基本数据类型的存储绝大多数情况下原始类型的值直接存在栈中。变量声明时引擎会在栈中划分一块区域把值直接放进去比如数字10布尔true。栈变量本身持有这个原始值不经过任何中间地址。⚠️ 有一些“特殊”的原始值如较长的字符串引擎内部可能会把它们放进堆而在栈上只存一个引用。这属于引擎优化但从逻辑语义上我们仍把字符串当作原始类型赋值时依然会复制行为上等同于直接存值。2. 对象数据类型的存储对象的数据实体始终存放在堆内存中而栈中只存储一个“门牌号”——即堆内存的引用地址。当你写let obj { name: Alice };引擎会做两件事在堆中分配一块内存存放对象{ name: Alice }得到一个地址比如0x003FFF。在栈中给变量obj分配空间里面存的值正是这个地址0x003FFF。访问obj.name时先通过栈里的地址找到堆中的对象再取出其属性。这种分工的原因在于对象大小可能在运行时随时变化增减属性把这种不稳定的数据放在容量有限、空间连续的栈里很危险。而栈只需保存一个固定大小的内存地址即可。四、存储方式按值 vs 按引用这是区分原始类型和对象类型最核心的行为差异。1. 原始类型 —— 按值存储和复制操作直接对“值”本身进行互不影响。leta10;letba;// 把 a 的值 10 复制一份给 bb20;console.log(a);// 10a 不变a 和 b 在栈中有各自独立的空间改一个不会影响另一个。2. 对象类型 —— 按引用存储和复制变量保存的是“引用地址”复制时只复制地址而不在堆里复制整个对象。letobj1{name:Alice};letobj2obj1;// 复制的是地址obj2 也指向堆里同一个对象obj2.nameBob;console.log(obj1.name);// Bobobj1 跟着变了obj1 和 obj2 里的地址相同因此通过任何一个变量修改对象都会反映在另一个上。函数的参数传递也遵守同样规则传原始类型函数内部修改形参不会影响外部实参。传对象修改对象属性会影响外部因为内外指向同一个对象。functionchange(num,obj){num100;// 改的是局部副本obj.nameZoe;// 改的是堆里的同一对象}letn1;leto{name:Tom};change(n,o);console.log(n);// 1未变console.log(o.name);// Zoe变了五、为什么要这样设计——深度理解性能与效率栈分配只需移动指针极快。原始类型大小已知、占用固定适合栈。对象如果直接放在栈中其动态扩展会引起大量内存搬移放在堆中栈上只保留一个指针保持高效。生命周期管理局部变量一般随函数退出销毁栈自动弹出。对象却可能被多个变量引用、逃逸出当前作用域堆配合垃圾回收能处理复杂存活分析。内存布局与安全性栈连续、有序容易产生栈溢出堆则分散。把不确定性大的对象放堆也让栈维持轻量安全。六、进阶那些“纯粹”之外的存储情况实际引擎如 V8会优化存储比如小整数Smi可能直接编码在指针里避免额外分配。字符串字符串常量池可能会在堆中存储但逻辑上仍是不可变的原始类型。复制字符串时通常表现为复制引用写时复制但对开发者透明行为仍符合“按值传递”。闭包引用的变量如果函数引用了外部原始类型变量这个变量会被移到堆中放在“环境”对象里从而延长生命周期。这时原始值确实存在了堆里但从语言视角它还是“原始值”只是存在位置变成了堆。这些实现细节不影响我们理解的大原则原始类型表现为“值语义”对象类型表现为“引用语义”栈负责快速管理大小固定的值或地址堆负责承载复杂动态的数据实体。七、总结堆栈定义栈是自动分配释放、有序快速的小容量区域堆是动态分配、靠 GC 回收的大容量区域。存储地方基本数据类型直接存于栈值本身对象实体存于堆栈里只留堆地址。存储方式基本类型按值复制对象类型按引用复制。设计意图兼顾性能与灵活性让小而短命的数据速生速灭大而长命的数据由堆和垃圾回收精细管理。理解这一模型后JavaScript 里赋值、传参、比较对对象比较地址等常见行为就都有了坚实的底层基础。