zoukankan      html  css  js  c++  java
  • JavaScript基础概念之----浅拷贝/深拷贝

    浅拷贝:就是简单的值的传递。

    深拷贝:达到了真正意义上的拷贝,很好的解决了引用类型的拷贝问题,采用递归的方法去复制拷贝对象,从而解决浅拷贝的弊端。

    在JS中,基本类型(Number,String,Boolean等)和 对象(Array,Object等)最大的不同在于它们的传值方式。基本类型是按值传递,对象按引用传值。

    var a = 1
    var b = 2
    b = 3
    console.log(a) //1
    console.log(b) //3
    //修改了b不会影响到a的值
    
    var oa = {a:1,b:2,c:3}
    var ob = oa;
    ob.a = 4
    console.log(oa) //{a:4,b:2,c:3} 被修改了
    console.log(ob) //{a:4,b:2,c:3}
    //修改了ob中属性的值,也会把oa中相同属性的值一起修改,因为它们根本就是同一个对象,这就是所谓的浅拷贝
    
    var o1 = {a:1,b:2,c:3}
    var o2 = {a:o1.a,b:o1.b,c:o1.c}
    o2.a = 4
    console.log(o1) //{a:1,b:2,c:3} 没有被修改
    console.log(o2) //{a:4,b:2,c:3}
    //这就是基本的深拷贝

    浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

    浅拷贝的实现方式

    1、简单的复制语句

    function copy(source){
        var target = {}
        for(var i in source){
            target [i] = source[i]
        }
        return target;
    }
    
    var o = {
        a:1,
        b:{ x:1,y:'hello'},
        c:[1,2,3],
        d:function(){
            console.log('hello')
        }
    }
    
    var clone = copy(o);
    console.log(clone) //输出clone对象
    
    clone.b.x = 2;
    clone.c = [4,5,6]
    clone.d = function(){console.log('world')}
    console.log(o) //输出o对象,o对象也被修改

    2、Object.assign()

    该方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,返回目标对象。

    var source = {
        a:{
            b:'hello',
            c:23
        }
    }
    
    var copy = Object.assign({},source )
    
    copy.a.b = 'world'
    console.log(source.a.b) // world source对象被修改

    注意:该方法可以处理一层的深度拷贝,如下:

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

    3、slice()和concat()

    var a = [1,{a:2},3]
    var b = a.slice(1,2)
    
    console.log(a) // [1,{a:2},3]
    console.log(b) // [{a:2}]
    
    b[0].a = 100;
    console.log(a) // [1,{a:100},3] 被修改了
    console.log(b) // [{a:100}]
    var a = [1,{a:2},3]
    var b = a.concat(4,5)
    
    console.log(a) // [1,{a:2},3]
    console.log(b) // [1,{a:2},3,4,5]
    
    b[1].a = 100;
    console.log(a) // [1,{a:100},3] 被修改了
    console.log(b) // [1,{a:100},3,4,5]

    深拷贝的实现方式

    1、手动复制

    即把一个对象的属性 复制 到另一个对象的属性上。

    要一个一个复制,很麻烦。并且这也不能算是真正的深拷贝,因为对象里面并未包含复杂类型(对象)

    var o1 = {a:1,b:2,c:3}
    var o2 = {a:o1.a,b:o1.b,c:o1.c}
    o2.a = 4
    console.log(o1) //{a:1,b:2,c:3} 没有被修改
    console.log(o2) //{a:4,b:2,c:3}
    var source = { a: { b:1 } }
    var copy = { a: source.a }
    
    copy.a.b = 2
    console.log(source.a.b) // 2 被修改了
    console.log(source === copy) //false
    console.log(source.a === copy.a) //true

    2、Object.assign()方法,对象只有一层深度时可以使用

    3、转成JSON再转回来

    JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。

    var source = { a: { b:1} }
    var copy = JSON.parse(JSON.stringify(source))
    
    copy.a.b = 2;
    
    console.log(source.a.b) //1 未被修改
    console.log(source === copy) //false
    console.log(source.a === copy.a) //false

    该方法缺点:

    • 会抛弃对象的constructor。不论对象原来的构造函数是什么,在深拷贝后都会变成Object。
    • 能正确处理的对象只有Number,String,Boolean,Array,扁平对象,即能被JSON直接表示的数据结构
    • RegExp对象无法通过这种方式深拷贝,即只有转成JSON格式的对象才可以使用,function无法转成JSON
    var source = {func:function(){}}
    var copy = JSON.parse(JSON.stringify(source))
    
    console.log(typeof source.func) //function
    console.log(typeof copy.func) //undefined

    4、递归拷贝

    function deepCopy(target,source){
        var o = target || {}
        for(var i in source){
            if(typeof source[i] === 'object'){
                o[i] = (source[i].constructor === Array) ? [] : {}
                arguments.callee(o[i],source[i])
            }else{
                o[i] = source[i]
            }
        }
        return o;
    }
    
    var target= {}
    var source = {a: { b:'hello',c:23 }}
    deepCopy(target,source)

    5、Object.create()

    function deepCopy(target,source){
        var o = target || {}
        for(var i in source){
            if(typeof source[i] === 'object'){
                o[i] = (source[i].constructor === Array) ? [] : Object.create(source[i])
           arguments.callee(o[i],source[i]) }
    else{ o[i] = source[i] } } return o; } var target= {} var source = {a: { b:'hello',c:23 }} deepCopy(target,source)

    6、jQuery 的 $.extend()

    var $ = require('jquery');
    var source = {
        a: 1,
        b: {x: { y: 1 } },
        c: [1, 2, 3]
    };
    var copy= $.extend(true, {}, source);
    
    console.log(source.b.x === copy.b.x);// false

    7、lodash 的 _.cloneDeep()

    var _ = require('lodash');
    var source= {
        a: 1,
        b: { x: { y: 1 } },
        c: [1, 2, 3]
    };
    var copy = _.cloneDeep(source);
    
    console.log(source.b.x=== copy.b.x);// false
  • 相关阅读:
    【EFCORE笔记】客户端与服务端求值&跟踪与非跟踪查询
    【EFCORE笔记】预先加载&显式加载&延迟加载
    【EFCORE笔记】在远程查询数据
    【EFCORE笔记】远程数据查询支持
    【EFCORE笔记】元素操作&集合运算&转换类型
    【EFCORE笔记】生成操作&相等比较&串联运算
    【EFCORE笔记】联接运算与数据分组
    【EFCORE笔记】投影运算与数据分区
    【EFCORE笔记】排序&集运算&筛选&限定
    【EFCORE笔记】团队环境中的迁移
  • 原文地址:https://www.cnblogs.com/adhehe/p/9790557.html
Copyright © 2011-2022 走看看