zoukankan      html  css  js  c++  java
  • 深入理解JavaScript中的堆与栈 、浅拷贝与深拷贝

    JavaScript中的浅拷贝与深拷贝

      学了这么长时间的JavaScript想必大家对浅拷贝和深拷贝还不太熟悉吧,今天在项目中既然用到了,早晚也要理清一下思路了,在了解之前,我们还是先从JavaScript的数据类型存放的位置 堆栈开始说起吧!           

    现在我们带着问题来学习!

    一:什么是堆栈?

      我们都知道:在计算机领域中,堆栈是两种数据结构,它们只能在一端(称为栈顶(top))对数据项进行插入和删除。

    • 堆:队列优先,先进先出;由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
    • 栈:先进后出;动态分配的空间 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。 
      以上都属于计算机基础部分,在此都不详细赘述了,下面我们联系JavaScript来剖析一下堆栈。

    二:JavaScript中的基本类型和引用类型与堆栈有什么联系?

    JavaScript的数据类型分为两大种: 
    1. 基本类型:Undefined、Null、Boolean、Number 和 String,这5中基本数据类型可以直接访问,他们是按照值进行分配的,存放在栈(stack)内存中的简单数据段,数据大小确定,内存空间大小可以分配。 
    2. 引用类型:即存放在堆(heap)内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。 
      以上我们知道了什么是堆栈,和JavaScript的数据类型,下面我们根据js的数据类型来说明一下他们的拷贝情况:

    var obj1 = {name:'bangbang',age:18};
    var b = obj1;
    var c = obj1.age;
    
    console.log(b.name); //bangbang
    console.log(c);      //18
    //改变b和c的值
    b.name = 'yanniu';
    c = 22;
    console.log(obj1.name);     //yanniu
    console.log(obj1.age);       //18

      以上看出:当我们改变b的数据的时候,我们看到了obj1.name的数据也在改变,但是我们改变c的数据的时候发现,obj1.age的值没有变化,这说明了:b和obj1变量操作的是同一个对象,c和obj1完全独立的。图示如下: 
    这里写图片描述

    三:什么是浅拷贝?

      根据上面的陈述,基本类型拷贝的时候只是在内存中又开辟了新的空间,和它的父元素(再次我们称被拷贝的对象为父元素)属于 互不想干的东西,因此深浅拷贝是相对于引用类型的,以便于我们对引用类型父对象的保存! 嘿嘿!我们接着看! 
    例如:

    var father1 = {name:'shangdi',age:1000,job:['teacher','cook']};
    //浅拷贝函数
    function copy(obj){
        var childs = {};
        for(var key in obj){
            childs[key] = obj[key];
        }
        return childs;
    }
    var child1 = copy(father1);
    console.log(child1);    //{ name: 'shangdi', age: 1000 }
    console.log(typeof child1); //object
    
    //改变子对象的name属性,发现对父对象的name没有影响 哈哈!
    child1.name = 'bangbang';
    console.log(father1);   //{ name: 'shangdi', age: 1000 }
    console.log(child1);    //{ name: 'bangbang', age: 1000 }
    
    //注意:这次改变子对象的job属性也就是改变数组,
    //发现对父对象的job竟然有影响,吓死宝宝了,那怎么办呢,那这个copy有什么用呢是吧!
    child1.job.push('programer');
    console.log(father1);   //{ name: 'shangdi',age: 1000,job: [ 'teacher', 'cook', 'programer' ] }
    console.log(child1);    //{ name: 'shangdi',age: 1000,job: [ 'teacher', 'cook', 'programer' ] }

    由上面可分析:浅拷贝的时候,当我们改变子对象的数组的时候,父对象竟然也跟着改变,也就是说:子对象和父对象在浅拷贝的时候他们指向同一个内存的数组:由图所示: 
    这里写图片描述 
    如果我们想让子对象的拷贝和父对象没有一点关联,那么我们就必须用到深度拷贝!嘿嘿!儿子也不能完全跟着爹长啊!

    四:什么是深度拷贝?

    深度拷贝就是把父对象拷贝到子对象上,而且两者的内存和以后的操作都互不影响的拷贝!

            function deepCopy(obj){
                var o;
                switch(typeof obj){
                case 'undefined': break;
                case 'string'   : o = obj + '';break;
                case 'number'   : o = obj - 0;break;
                case 'boolean'  : o = obj;break;
                case 'object'   :
                    if(obj === null){
                        o = null;
                    }else{
                        if(obj instanceof Array){
                            o = [];
                            for(var i = 0, len = obj.length; i < len; i++){
                                o.push(deepCopy(obj[i]));
                            }
                        }else{
                            o = {};
                            for(var k in obj){
                                o[k] = deepCopy(obj[k]);
                            }
                        }
                    }
                    break;
                default:
                    o = obj;break;
                }
                return o;
            }

    这里写图片描述 
       下面是一些克隆的方法供大家参考,不过他们有区别,自己试验: 
    方法二:最简单的

        function deepCopy(obj) {
            return JSON.parse(JSON.stringify(obj));
        }

    方法三:

            function deepCopy(obj){
                var newobj, obj;
                if (obj.constructor == Object){
                    newobj = new obj.constructor();
                }else{
                    newobj = new obj.constructor(obj.valueOf());//valueOf()方法返回 Array 对象的原始值
                }
                for(var key in obj){
                    if ( newobj[key] != obj[key] ){
                        if ( typeof(obj[key]) == 'object' ){
                            newobj[key] = deepCopy(obj[key]);
                        }else{
                            newobj[key] = obj[key];
                        }
                    }
                }
                newobj.toString = obj.toString;
                newobj.valueOf = obj.valueOf;
                return newobj;
            }

    方法四:

    var cloneObj = function(obj){
        var str, newobj = obj.constructor === Array ? [] : {};
        if(typeof obj !== 'object'){
            return;
        } else if(window.JSON){
            str = JSON.stringify(obj), //系列化对象
            newobj = JSON.parse(str); //还原
        } else {
            for(var i in obj){
                newobj[i] = typeof obj[i] === 'object' ? 
                cloneObj(obj[i]) : obj[i]; 
            }
        }
        return newobj;
    };

    方法五:(JavaScript面向对象编程指南)

        function deepCopy(p,c){
            c = c || {};
            for (var i in p){
                if(p.hasOwnProperty(i)){
                    if(typeof p[i] === 'object'){
                        c[i] = Array.isArray(p[i]) ? [] : {};
                        deepCopy(p[i],c[i]);
                    }else{
                        c[i] = p[i];
                    }
                }
            }
            return c;
        }
  • 相关阅读:
    leetcode 279. Perfect Squares
    leetcode 546. Remove Boxes
    leetcode 312. Burst Balloons
    leetcode 160. Intersection of Two Linked Lists
    leetcode 55. Jump Game
    剑指offer 滑动窗口的最大值
    剑指offer 剪绳子
    剑指offer 字符流中第一个不重复的字符
    leetcode 673. Number of Longest Increasing Subsequence
    leetcode 75. Sort Colors (荷兰三色旗问题)
  • 原文地址:https://www.cnblogs.com/mei123/p/8694943.html
Copyright © 2011-2022 走看看