zoukankan      html  css  js  c++  java
  • js中的浅拷贝和深拷贝

    一、浅拷贝和深拷贝

    (1)基本类型

      5种基本数据类型,Number、String、Boolean、Null以及Undefined,变量是直接按值存放的,存放在栈内存中的简单数据,可以直接访问。

    (2)引用类型

      存放在堆内存中的对象,变量保存的是一个指针,这个指针指向另一个位置。

      当需要访问引用类型(比如对象,数组)时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

    浅拷贝

      如下面代码所示:

    var x = {
        a:1,
        b:2
    };
    var y = x;
    y.a = 3;
    console.log(x);//{a: 3, b: 2}
    console.log(y);//{a: 3, b: 2}

      这是浅拷贝,x和y指向的是同一个堆,对象复制只是复制的对象的引用

      复制的副本其实只是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受影响

    深拷贝

      如下面代码所示:

    var x = {
        a:1,
        b:2
    };
    var y = {
        a:x.a,
        b:x.b
    };
    y.a = 3;
    console.log(x);//{a: 1, b: 2}
    console.log(y);//{a: 3, b: 2}

      x对象和y对象是虽然所有的值都是一样的,但是在堆里面,对应的不是同一个了。

    深拷贝和浅拷贝的示意图如下:

      浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。

       但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

     二、浅拷贝的实现方式

    1.通过赋值实现

      将浅拷贝封装成一个函数,如下代码所示:

    function shallowCopy (src) {
        var result = {};
        for(let prop in src){
            result[prop] = src[prop];
        }
        return result;
    }
    var obj = {
        a:1,
        arr:[2,3]
    };
    var shallowObj = shallowCopy(obj);
    shallowObj.arr[1] = 5;
    console.log(obj);
    console.log(shallowObj);

      结果如下图所示:

    2.通过Object.assign()实现

      Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。

      但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

      如下面代码所示:

    var x = {
        a:{
            b:1,
            c:2
        }
    };
    var y = Object.assign({},x);
    y.a.b = 3;
    console.log(x);//{a:{b:3,c:2}}
    console.log(y);//{a:{b:3,c:2}}

      注意:当object只有一层的时候,是深拷贝,如下代码所示:

    var x = {
        a:1,
        b:2
    };
    var y = Object.assign({},x);
    y.a = 3;
    console.log(x);//{a: 1, b: 2}
    console.log(y);//{a: 3, b: 2}

    三、深拷贝的实现方式

    1.当对象只有一层时,通过Object.assign()实现,如上

    2.JSON对象的stringify以及parse方法

      JSON.stringify方法将js对象序列化成JSON字符串,JSON.parse方法将JSON字符串反序列化为js对象。

      借助这两个方法,可以实现对象的深拷贝。

    var x = {
        a:1,
        b:2
    };
    var y = JSON.parse(JSON.stringify(x));
    y.a = 3;
    console.log(x);//{a: 1, b: 2}
    console.log(y);//{a: 3, b: 2}

    3.jQuery 的$.extend方法

    var $ = require('jquery');
    var obj1 = {
        a: 1,
        b: { f: { g: 1 } },
        c: [1, 2, 3]
    };
    var obj2 = $.extend(true, {}, obj1);
    console.log(obj1.b.f === obj2.b.f);// false

     4.原生js实现深拷贝

    function deepCopy(obj) {
        if(obj === null){
            return obj;
        }
        //定义一个结果变量为newobj,判断结果为数组还是对象
        let newobj = Array.isArray(obj)?[]:{};
        for(let key in obj){
            //如果是对象应该深拷贝,在堆内存中开辟新的内存,递归实现,否则进行浅拷贝
            if(typeof obj[key] === 'object'){
                newobj[key] = deepCopy(obj[key]);
            }else {
                newobj[key] = obj[key];
            }
        }
        return newobj;
    }
    //测试数据如下
    let Obj = {a:1,b:{c:2,d:3}};
    let newobj = deepCopy(Obj);
    newobj.a=5;
    console.log(Obj);//{a:1,b:{c:2,d:3}}
    console.log(newobj);//{a:5,b:{c:2,d:3}}
    
    let arr = [1,2,3,[4,5,6]];
    let newarr = deepCopy(arr);
    newarr[0]=7;
    console.log(arr);//[1,2,3,[4,5,6]]
    console.log(newarr);//[7,2,3,[4,5,6]]
  • 相关阅读:
    Tomcat 三种运行方式
    MariaDB介绍
    Nginx 平滑升级
    代理命令 proxy_pass 详解
    Nginx 和 Tomcat 负载均衡
    基于Apache和tomcat实现负载均衡
    centos7 通过源码编译的方式安装和配置Apache
    基于nginx结合openssl实现https
    HTTP 和 HTTPS 区别
    linux系统中修改别名配置文件,构建命令别名
  • 原文地址:https://www.cnblogs.com/gg-qq/p/10862090.html
Copyright © 2011-2022 走看看