JavaScript 中的变量分为基本类型和引用类型,对变量的存储主要有两种位置,堆内存和栈内存。
栈内存主要用于存储各种基本类型的变量,包括 Boolean、Number、String、Undefined、Null,以及对象变量的指针。栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储。一般情况下,当函数执行完成,所形成的私有作用域(栈内存)都会自动释放掉,但是也有特殊的情况(闭包)。
主要负责像对象 Object 这种变量类型的存储,而堆内存存储的对象类型数据对于大小这方面,一般都是未知的。堆内存利用空对象指针 null 来释放空间。JavaScript 不允许直接访问堆内存中的位置,因此操作对象时,实际操作对象的引用,当我们要访问堆内存中的引用数据类型时,首先要先从栈内存获得该对象的地址,然后再从堆内存中取得数据。
基本类型在当前执行环境结束时销毁,而引用类型只有当所有引用它的变量都不存在时这个对象才被垃圾回收机制回收。
堆内存 | 栈内存 |
---|---|
存储基本数据类型 | 存储引用数据类型 |
直接访问数值 | 按照引用访问 |
存储空间系统分配 | 可自定义存储空间 |
先进后出 | 无序存储 |
栈是一种受限的线性表,只允许在栈顶进行插入(入栈)和删除(出栈)操作,相应的另一端称之为栈底。拥有“先进后出”的特性 FILO。栈分顺序栈(元素地址连续)和链式栈(元素地址不连续)两种。
堆是一种常用的树形结构,是一种特殊的完全二叉树,当且仅当满足所有节点的值总是不大于或不小于其父节点的值的完全二叉树被称之为堆。如果根节点最小,称之为小顶堆,如果根节点最大,称之为大顶堆。
堆的存储一般都用数组来存储堆,i 节点的父节点下标就为(i–1)/2。它的左右子节点下标分别 2∗i+1 和 2∗i+2
浅拷贝 是 发生在栈中的拷贝行为,只能拷贝基本值和引用值的地址。
深拷贝 是 同时发生在栈中和堆中的拷贝行为,除了拷贝基本值和引用值的地址之外,地址指向的堆中的对象也会发生拷贝。
一般我们说 用 const 定义的变量是不可变的,这只是笼统的说法。当我们定义一个 const 对象的时候,我们说的常量其实是指针,就是 const 对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或者属性是可变的。