logo

JavaScript 中的栈与堆详解

本站 4533
在深入探讨 JavaScript 运行机制时,内存管理是一个至关重要的概念。其中两个核心部分是栈(Stack)和堆(Heap),它们各自负责存储不同类型的数据,并对程序性能、执行效率乃至垃圾回收等方面产生直接影响。

### 栈:线性且有序的空间

首先从“栈”说起,在计算机科学中,“栈”是一种遵循后进先出原则(Last In First Out, LIFO)的数据结构。对应到JavaScript环境中,它主要用来存放基本类型数据以及对应的引用地址。这些基础类型的值包括但不限于:

- 布尔型 (boolean)
- 整数/浮点数数值(number)
- 字符串(string)
- 空(null)
- 未定义(undefined)

当声明一个变量并将上述的基本类型赋给该变量时,这个变量就会被直接压入当前作用域内的栈空间内,它的生命周期伴随着其所在的作用域结束而销毁。

例如:
javascript

function test() {
let num = 10; // 'num'及它的值(整数10),会被存放在栈里。
}
test();
// 在调用完函数之后,'num'及其占用的栈空间将自动释放掉.


### 堆:动态分配的大仓库

相比于严格规则下的栈区,"堆"(Heap)则更像是一个可以自由伸缩并用于储存复杂数据类型的大型池子。在JavaScript中的对象(Object), 数组(Array), 函数(Function), 正则表达式(RegExp)等都是保存在这片区域。

每当创建一个新的复合类型实例时,JS引擎会在堆上为其开辟一块新的内存空间来存储其实例内容。然后返回指向这块内存位置的一个指针或者说引用(reference),将其储存在栈或者其它已经存在的堆上的对象属性之中。

举例来说,
javascript

let obj = {name: "Alice"};
// 首先在堆上为{name:"Alice"} 创建了一个新对象;
// 然后把该对象所在的堆内存地址赋予了`obj`变量,这个变量就存在于栈上了;
console.log(obj.name); // 输出"Alice"

在这个例子中,对象 `{name: "Alice"}` 存在于堆内存中,而在 `obj` 只存储的是对该堆内存区块的引用。

### 引用传递与复制行为差异

由于这种栈存储原始值、堆存储实际对象的设计方式,使得不同类型的变量之间存在着明显的交互区别。对于基本类型而言,进行操作如赋值或作为参数传参时实际上是进行了拷贝;而对于包含堆地址的对象,则是在不同的上下文中共享同一份实体资源,这就是所谓的“按引用传递”。

总结起来,理解JavaScript中的栈与堆的概念有助于我们更好地掌握代码运行背后的原理,合理地优化内存使用策略,进而提升应用程序的整体表现力。通过精心设计我们的编程逻辑以减少不必要的内存开销,亦或是高效利用闭包特性处理那些需要跨作用域持久化的状态问题等等,这些都是基于对栈与堆工作机理透彻了解后的自然产物。

标签: 栈和堆js