JS中的栈和堆

部署运行你感兴趣的模型镜像

学过数据结构的同学对于栈和堆都多少有点了解吧!不了解也没关系,学习JS中的栈和堆也一样的^_^,下面我们来看看栈和堆到底是何方神圣……

一.栈和堆

栈(stack):栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间。
基本类型:String,Number,Boolean,Null,Undefined

堆(heap):动态分配的内存,大小不定也不会自动释放,存放引用类型,指那些可能由多个值构成的对象,保存在堆内存中,包含引用类型的变量,实际上保存的不是变量本身,而是指向该对象的指针。
引用类型:Function,Array,Object

二.区别

:所有在方法中定义的变量都是放在栈内存中,随着方法的执行结束,这个方法的内存栈也自然销毁。

优点:存取速度比堆快,仅次于直接位于CPU中的寄存器,数据可以共享;
缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

:堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(参数传递)。创建对象是为了反复利用,这个对象将被保存到运行时数据区。

三.栈和堆的溢出

:可以递归调用方法,这样随着栈深度的增加,JVM维持着一条长长的方法调用轨迹,知道内存不够分配,产生栈溢出。
:循环创建对象,通俗点就是不断的new 一个对象。

下面来看看传值和传址的区别
其实这两者区别就是基本类型和引用类型的区别,话不多说看栗子

var a = [1,0,9,8,7];
   var b = a;
   var c = a[0];
   console.log(b);     //[1,0,9,8,7]
   console.log(c);     //1
   //改变数值
   b[1] = 3;
   c = 5;
   console.log(b[1]);  //3
   console.log(a[0]);  //1      

因为a是数组,是引用类型,赋给b的时候传的是栈中的地址,不是堆内存中的对象,c仅仅是从a堆内存中获取的一个数据值,并保存在栈中,所以b修改的时候,会根据地址回到a堆中修改,c则直接在栈中修改,并且不能指向a堆内存中。

四.深浅拷贝

深浅拷贝在前端面试中经常被问到,和大家分享一下,先来说说浅拷贝
浅拷贝:也就是只复制了第一层属性,复制对象是基本类型
在复制基本类型时,直接使用等号完成,在复制引用类型时,循环遍历对象,对每个属性或值使用等号完成。

下面看个栗子

var color1 = ['red','green']; 
        var color2 = [];
        //复制
        for(var i  = 0;i < color1.length;i++){
          color2[i] = color1[i]; 
        }
        console.log(color2);  //[red,green]
        color1.push('black');
        console.log(color2);  //[red,green]

在这个栗子中,color2复制color1,因为数组中的每一项都是基本类型(string),假如数组中的某一项保存的是一个对象,或者是一个数组,又或者说对象的某一个属性还是一个对象(也就是引用类型的某个属性还是引用类型),此时浅拷贝就没用了,那该怎么办?
我们先来看一个引用类型属性还是引用类型的栗子(有点绕口…..)

var person = {
    name : 'wang',
    score:{
            math:100,
        English:100
        }
    }

在上面这个小栗子中,score属性还是一个对象。

下面继续来说我们的拷贝,现在该深拷贝出场了……
深拷贝:对属性中所有引用类型的值,遍历到是基本类型的值为止,利用递归来实现深拷贝。
来看一个栗子

function cloneObject (obj) {
     var newObj = {}  //如果不是引用类型,直接返回
      if (typeof (obj) !== 'object') {
          return obj
     }
     //如果是引用类型,遍历属性
    else{
        for (var attr in obj) {
        //如果某个属性还是引用类型,递归调用
        newObj[attr] = cloneObject(obj[attr])
                }
       }
    return newObj
  }

对于深拷贝,我们先判断它是否为引用类型,如果不是,直接返回
如果是,循环遍历该对象的属性,如果某个属性还是引用类型,则针对该属性再次调用deepClone函数。

您可能感兴趣的与本文相关的镜像

Kotaemon

Kotaemon

AI应用

Kotaemon 是由Cinnamon 开发的开源项目,是一个RAG UI页面,主要面向DocQA的终端用户和构建自己RAG pipeline

### JavaScript 中的区别联系 #### 区别 1. **存储内容** - 主要用来存储基本类型的值以及引用类型变量的地址。这些数据通常是临时性的,生命周期较短[^1]。 - 主要用于存储复杂对象的实际数据(如对象、数组等)。这些数据通常具有较长的生命周期[^2]。 2. **内存分配方式** - 的内存分配是由编译器解释器自动完成的,遵循严格的顺序进出原则(LIFO, Last In First Out),即最后进入的数据最先被移除[^3]。 - 的内存分配则是动态的,开发者可以手动创建对象并将其存放在中,而释放则依赖于垃圾回收机制来清理不再使用的对象[^4]。 3. **内存大小** - 的空间有限且固定,适合存储少量的小型数据。 - 的空间更大且灵活,能够容纳复杂的大型数据结构。 4. **访问速度** - 由于的操作简单且连续,因此访问速度较快。 - 因为涉及更多的寻址操作,所以访问速度相对较慢。 5. **回收机制** - 当函数执行完成后,上的局部变量会被立即销毁,无需额外干预。 - 对于中的对象,则需要等待垃圾收集器检测到该对象不可达时才会进行清理。 #### 联系 尽管两者在功能上有显著差异,但在实际应用过程中也存在着紧密的合作关系: - 变量声明时如果是一个基础数据类型,则直接将数值放入区;如果是引用数据类型,则会在里保存一个指向区内真实数据位置的指针[^4]。 - 函数调用期间不仅利用记录必要的上下文信息以便返回后继续运行原流程,同时也可能间接影响到上某些资源的状态改变情况,例如修改某个全局或者外部作用域内的大尺寸实体属性值等等。 ```javascript function exampleFunction() { const primitiveValue = 10; // 存储在中 const complexObject = { name: 'John', age: 30 }; // 实际对象存储在中 console.log(primitiveValue); // 访问中的原始值 console.log(complexObject.name); // 通过中的引用访问中的对象成员 } exampleFunction(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值