zoukankan      html  css  js  c++  java
  • 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函数。



    作者:WANG_M
    链接:https://www.jianshu.com/p/67c0323aef1e
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    Winsock 2 入门指南
    Winsock 2 入门指南
    [手游新项目历程]-40-linux环境实现C/C++程序崩溃退出时打印栈信息
    1月下旬解题
    poj1226,poj3080
    poj3666
    poj3067
    poj12月其他题解(未完)
    poj1823,3667
    poj2352
  • 原文地址:https://www.cnblogs.com/blueball/p/12454240.html
Copyright © 2011-2022 走看看