# JS的堆内存和栈内存

首先思考一个问题:

Q: const定义的值能改吗?

A: const定义的基本类型不能改变,但是定义的对象是可以通过修改对象属性等方法来改变的

示例:

const a = 4
a = 8 //报错 Uncaught TypeError: Assignment to constant variable

const b = { name: '木木' }
b.name = '木子' // b 此时为 {name: '木子'}
b = {} // 报错 Uncaught TypeError: Assignment to constant variable
1
2
3
4
5
6

const 为什么可以修改? 这里就涉及到了js引擎中对变量的存储

# 堆内存和栈内存

在js引擎中对变量的存储主要有两种位置,堆内存和栈内存

栈内存主要存储js的5种基本类型:Undefined、Null、Boolean、Number和String

堆内存主要存储引用类型的数据:如对象(Object)、数组(Array)、函数(Function)

各种语言在处理堆栈的原理上都大同小异。堆是动态分配内存,内存大小不一,也不会自动释放。栈是自动分配相对固定大小的内存空间,并由系统自动释放

栈,线性结构,后进先出,便于管理
堆,一个混沌,杂乱无章,方便存储和开辟内存空间

注意

引用类型的数据的地址指针是存储于栈中的,当我们想要访问引用类型的值的时候,需要先从栈中获得对象的地址指针,然后,在通过地址指针找到堆中的所需要的数据,可以看下面的图理解

An image

栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储。而堆内存存储的对象类型数据对于大小这方面,一般都是未知的

因此当我们定义一个const对象的时候,我们说的常量其实是指针,就是const对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或者属性是可变的。而对于const定义的基础变量而言,这个值就相当于const对象的指针,是不可变

我们知道let可以定义块级作用域,上面了解js内存的存储,解释const、let定义的变量不能二次定义的流程也就比较容易理解了,每次使用const或者let去初始化一个变量的时候,会首先遍历当前的内存栈,看看有没有重名变量,有的话就返回错误

# 内存分配和垃圾回收

栈内存线性有序存储,容量小,系统分配效率高
堆内存首先要在堆内存新分配存储区域,之后又要把指针存储到栈内存中,效率相对就要低一些

栈内存变量基本上用完就回收了,而堆内存中的变量因为存在很多不确定的引用,只有当所有调用的变量全部销毁之后才能回收