JS数据如何存储

71 阅读2分钟
1. 数据是如何存储的?
    1.1. 基本数据类型用 栈 存储,引用数据类型用 堆 存储。  
    1.2. 看起来没有错误,但实际上是有问题的。可以考虑一下闭包的情况,如果变量存在栈中,那函数调用完栈顶空间销毁 ,闭包变量不就没了吗?  
    1.3. 其实还是需要补充一句:闭包变量是存在堆内存中的。  
    
    
2. 具体而言,以下数据类型存储在栈中:  
        boolean  
        null
        undefined  
        number  
        string  
        symbol  
        bigint  
3. 而所有的对象数据类型存放在堆中。  


4. *****值得注意的是*****,对于赋值操作,原始类型的数据直接完整地复制变量值,对象数据类型的数据则是复制引用地址。  
    4.1. 因此会有下面的情况:
        let obj = { a: 1 };  
        let newObj = obj;  
        newObj.a = 2;  
        console.log(obj.a);//变成了2
    4.2. 之所以会这样,是因为 obj 和 newObj 是同一份堆空间的地址,改变newObj,等于改变了共同的堆内存,这时候通过 obj 来获取这块内存的值当然会改变。
    
   
5. 为什么不全部用栈来保存呢?  
    5.1. 首先,对于系统栈来说,它的功能除了保存变量之外,还有创建并切换函数执行上下文的功能。举个例子:
        function f(a) {  
            console.log(a);  
        }   
        function func(a) {  
            f(a);  
        }   
        func(1);
        //结果:1
    5.2. 假设用ESP指针来保存当前的执行状态,在系统栈中会产生如下的过程:  
        1)调用func, 将 func 函数的上下文压栈,ESP指向栈顶。  
        2)执行func,又调用f函数,将 f 函数的上下文压栈,ESP 指针上移。  
        3)执行完 f 函数,将ESP 下移,f函数对应的栈顶空间被回收。  
        4)执行完 func,ESP 下移,func对应的空间被回收。  
        图示如下:
image.png
    5.3. 因此,如果采用栈来存储相对基本类型更加复杂的对象数据,那么切换上下文的开销将变得巨大!  
    5.4. 不过堆内存虽然空间大,能存放大量的数据,但与此同时垃圾内存的回收会带来更大的开销。
    
    
  6. 为什么基础数据类型存在栈中,而引用数据类型存在堆中呢?
        6.1.  堆比栈大,栈比堆速度快。
        6.2.  基础数据类型比较稳定,而且相对来说占用的内存小。
        6.3.  引用数据类型大小是动态的,而且是无限的。
        6.4.  堆内存是无序存储,可以根据引用直接获取。