一、为什么要把内存分成栈内存和堆内存?
每次执行项目代码时,系统都会为其分配一块内存。
项目代码运行时,有不同的对于内存的需求,因此需要将分配到的内存划分成几个部分加以利用。
每种编程语言的内存划分方式都不同,取决于它自身的特点。
而 JS 将内存划分成了代码内存、栈内存和堆内存。
其中,代码内存专门用来保存可执行代码,暂且不提。
1.1 栈内存与执行上下文
之前的文章里讲过函数调用栈这个概念。执行代码时,会将全局执行上下文和正在执行的函数上下文压入调用栈中。
这里说的栈,就是存储在栈内存里。
也就是说,栈内存最大的作用,就是存储执行上下文。
每当一个函数执行完毕,就会将指针指向上一个函数,执行完毕的函数上下文就会被垃圾回收,从而释放它所占用的内存空间。
二、栈内存和堆内存都存的是什么?
2.1 JS 的数据类型-原始类型和引用类型
JS 中的数据类型可简单分为两种:原始类型和引用类型。它们在存储方式上有很大的不同。
看一个例子:
function foo() {
var a = 1
var obj = {
name: 'xiaoming'
}
}
foo()
当执行这段代码时,它们是被这样存储的:

9D1A3FD3-EE17-44DD-BCAB-C1D109811CA8.png
原始类型的值会直接存储在上下文中,而上下文则存储在栈内存中;
引用类型的值实际上会被存储在堆内存中,每一个值都对应着一个地址,然后在栈内存的执行上下文中奖变量的值赋值成对应的地址。
2.2 为什么引用类型要存储在堆内存中?
上面讲到了,栈内存的主要作用是存储函数调用栈,JS 引擎依靠栈来维护程序执行期间上下文的状态,如果所有数据都存储在栈内存中,会影响到上下文切换的效率,进而影响整个程序的执行效率。
出于这种考虑,将引用类型的值(需要的存储空间相对更大)存在堆内存,而在栈内存中存储它的地址。