JS 学习 之 栈与堆

149 阅读2分钟

JS的内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)。其中栈存放变量,堆存放复杂对象,池存放常量,所以也叫常量池

变量类型与内存关系

基本数据类型

  1. String
  2. Number
  3. Boolean
  4. null
  5. undefined
  6. Symbol

基本数据类型保存在栈内存中,因为基本数据类型占用空间小、大小固定,通过按值来访问,属于被频繁使用的数据。

引用数据类型

Array,Function,Object...可以认为除了上文提到的基本数据类型以外,所有类型都是引用数据类型。

引用数据类型存储在堆内存中。因为引用数据类型占据空间大、大小不固定。 如果存储在栈中,将会影响程序运行的性能。因此, 引用数据类型只是在栈中存储了一个指针,该指针指向堆中的该实体。 当解释器寻找引用值时,会首先检索其在栈中的地址,从栈取得地址在堆中获得实体。

从内存角度看变量复制

基本数据类型的复制

let a = 20;
let b = a;
b = 30;
console.log(b); // 30
console.log(a); // 20

栈遵循 后进先出 原则:声明一个变量,多次赋值取最后一个值。

a、b 都是基本数据类型,它们的值是存储在栈内存中的,a、b 分别有各自独立的栈空间, 所以修改了 b 的值以后,a 的值并不会发生变化。

引用数据类型的复制

let m = { a: 10, b: 20 };
let n = m;
n.a = 15;
console.log(m.a); //15

m、n都是引用数据类型,栈内存中存放的地址指向堆内存中的对象。 引用类型的复制会为新的变量自动分配一个新的值保存在栈内存中, 但只是引用类型的一个地址指针而已,实际指向的是还是同一个对象。也就是说m、n是同一个地址指针,而指针是没有变的。

栈内存和堆内存的垃圾回收

栈内存中变量一般在它的当前执行环境结束就会被销毁被垃圾回收制回收, 而堆内存中的变量则不会,因为不确定其他的地方是不是还有一些对它的引用。 堆内存中的变量只有在所有对它的引用都结束的时候才会被回收。

闭包与堆内存

闭包中的变量并不保存中栈内存中,而是保存在堆内存中。 这也就解释了函数调用之后为什么闭包还能引用到函数内的变量。

参考:

  1. 「前端进阶」JS中的栈内存堆内存