JS中的栈和堆

JS中的栈和堆学过数据结构的同学对于栈和堆都多少有点了解吧!不了解也没关系,学习JS中的栈和堆也一样的^_^,下面我们来看看栈和堆到底是何方神圣……一.栈和堆栈(stack):栈会自动分配内存空间,会自动释放,存放基本类型,简单的数据段,占据固定大小的空间。基本类型:String,Number,Boolean,Null,Undefined堆(heap):动态分配的内存,大小不定也不会自动释放,存放引用类型,指

学过数据结构的同学对于栈和堆都多少有点了解吧!不了解也没关系,学习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函数。

今天的文章JS中的栈和堆分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/5458.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注