JavaScript中栈内存与堆内存分别是什么?

        在js引擎中对变量的存储主要有两个位置,堆内存和栈内存栈内存主要用于存储各种基本类型的变量,包括Boolean、Number、String、Undefined、Null,以及对象变量的指针(地址值)。栈内存中的变量一般都是已知大小或者有范围上限的,算作一种简单存储。而堆内存主要负责像对象Object这种变量类型的存储,对于大小这方面,一般都是未知的。

JavaScript中栈内存与堆内存分别是什么?_第1张图片

        当我们定义一个const对象的时候,我们说的常量其实是指针(假设e所指向的内存空间地址值为0x123,那么e的值就是0x123),const对象对应的堆内存地址值是不变的,但是堆内存中的数据本身的大小或者属性是可变的。而对于const定义的基础变量类型而言,这个值就是真实的值了,都不可变。当我们把var,const,let定义的常量或者变量赋值给其他变量时,其实是将真实的地址值进行了赋值操作。

        为什么const、let定义的变量不能二次定义

        既然知道了const在内存中的存储,那么const、let定义的变量不能二次定义的流程也就比较容易猜出来了,每次使用const或者let去初始化一个变量的时候,会首先遍历当前的内存栈,看看有没有重名变量,有的话就返回错误。

        new关键字初始化的时候是不是存储在栈内存中

        new会根据构造函数生成新实例,这个时候生成的是对象,而不是基本类型。

let a = new String('行则将至')
let b = new String('行则将至')
console.log(a == b, a === b) // false false

        可以很明显的看出来,如果a,b是存储在栈内存中的话,两者应该是明显相等的,但结果两者并不相等,说明两者都是存储在堆内存中的,指向的地址值不一致。 

        说到这里,再去想一想我们常说的值类型和引用类型其实说的就是栈内存变量和堆内存变量,再想想值传递和引用传递、深拷贝和浅拷贝,都是围绕堆内存和栈内存展开的,一个是处理,一个是处理(地址值)。

        内存分配和垃圾回收

        一般来说栈内存是线性有序存储,容量小,系统分配效率高。而堆内存首先要在堆内存新分配存储区域,之后又要把指针(地址值)存储到栈内存中,效率相对就要低一些了。
        垃圾回收方面,栈内存变量基本上用完就回收了,而推内存中的变量因为存在很多不确定的引用,只有当所有指向堆内存的指针全部销毁之后才会被垃圾回收。所以,使用匿名函数当调用完函数之后把储存在栈内存中的指针赋值为null也是一种优化性能防止内存泄漏的一种方式。

你可能感兴趣的:(JavaScript进阶,javascript,前端)