在javascript中,我们每定义一个变量,系统会自动为其分配内存来存储该变量,由于变量值有不同的数据类型,JS的内存空间又划分为栈(stack)、堆(heap)、池(一般也会归类为栈中),来存储不同的数据类型。相应的我们使用该变量,就使用(占用)了内存。
var a = 10; // 分配内存
console.log(a); // 对内存的使用
其中,
- 栈内存存放基本数据类型。
- 堆内存存放引用数据类型。
1.数据类型
基本数据类型共有6种:
- Sting
- Number
- Boolean
- null
- undefined
- Symbol
引用数据类型共有3种:
- Array
- Function
- Object
2.栈内存
- 基本数据类型保存在栈内存中,因为基本数据类型占用空间小、大小固定,通过按值来访问,属于被频繁使用的数据。
为了更好的搞懂基本数据类型变量与栈内存,我们结合以下例子与图解进行理解:
let num1 = 1;
let num2 = 1;
- 栈内存存取的特点是,
先进后出,后进先出
,由上图可以看出num2在最下面 - 注意闭包中的基本数据类型变量不保存在栈内存中,而是保存在堆内存中。下面会讲到
3.堆内存
- 引用数据类型保存在堆内存中,因为引用数据类型占据空间大、大小不固定。 如果存储在栈中,将会影响程序运行的性能
- 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体
- 堆内存存取的特点是
随意存取
,不存在先进后出,后进先出
的特点,这就如同我们在图书馆的书架上取书, 虽然书的摆放是有顺序的,但是我们想取任意一本时不必像栈一样,先取出前面所有的书, 我们只需要关心书的名字。
为了更好的搞懂变量对象与堆内存,我们结合以下例子与图解进行理解。
// 基本数据类型-栈内存
let a1 = 0;
// 基本数据类型-栈内存
let a2 = 'this is string';
// 基本数据类型-栈内存
let a3 = null;
// 对象的指针存放在栈内存中,指针指向的对象存放在堆内存中
let b = { m: 20 };
// 数组的指针存放在栈内存中,指针指向的数组存放在堆内存中
let c = [1, 2, 3];
因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从变量中获取了该对象的地址指针, 然后再从堆内存中取得我们需要的数据。
4.栈内存和堆内存的优缺点
- 在JS中,基本数据类型变量大小固定,并且操作简单容易,所以把它们放入栈中存储。
- 引用类型变量大小不固定,所以把它们分配给堆中,让他们申请空间的时候自己确定大小,这样把它们分开存储能够使得程序运行起来占用的内存最小。
- 栈内存由于它的特点,所以它的系统效率较高。堆内存需要分配空间和地址,还要把地址存到栈中,所以效率低于栈。
5.栈内存和闭包
- 栈内存中变量一般在它的当前执行环境结束就会被销毁被垃圾回收制回收, 而堆内存中的变量则不会,因为不确定其他的地方是不是还有一些对它的引用。 堆内存中的变量只有在所有对它的引用都结束的时候才会被回收。
- 闭包中的变量并不保存中栈内存中,而是保存在堆内存中。因为闭包通常返回了一个引用,如果该引用没有手动解除,局部活动对象仍然留在内存中。