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函数。

    https://www.jianshu.com/p/67c0323aef1e

  • 相关阅读:
    Apache Flink 1.12.1发布
    flink 修改web页面刷新时间
    flink 支持的sql 方言
    flink sql 读取hive 表报错
    Typora配置正文、目录、侧边大纲中的标题自动编号
    滴滴开源Logi-KafkaManager 一站式Kafka监控与管控平台
    建立 nfs 服务器
    Linux 设备驱动的第一个例子 。
    备份.vimrc
    shell编程实例
  • 原文地址:https://www.cnblogs.com/xzybk/p/12528230.html
Copyright © 2011-2022 走看看