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

    JavaScript的数据类型有:

    基本数据类型:Number、String、Boolean、null、undefined (栈内存)

    引用数据类型:Object (堆内存)

    保存在栈内存还是堆内存的根本原因是什么?

    根本原因在于保存在栈内存的必须是大小固定的数据,引用类型的大小不固定,只能保存在堆内存中,但是可以把它的地址写在栈内存中以供我们访问

    如果是基本数据类型,则按值访问,操作的就是变量保存的值;如果是引用类型的值,我们只是通过保存在变量中的引用类型的地址来操作实际对象

    基本类型的复制
    var a = 1;
    var b = a;//复制
    console.log(b)//1
    a = 2;//改变a的值
    console.log(b)//1
    

    基本类型在复制时,相当于在栈内存中重新开辟了一个内存,存放变量b,因此在修改a时,b和a互不影响

    引用类型的复制
    var color1 = ['red','green'];
    var color2 = color1;//复制
    console.log(color2)//['red','green'];
    color1.push('black') ;//改变color1的值
    console.log(color2)//['red','green','black']
    

    引用类型在复制时,相当于复制的是某个对象的指针(即引用地址),而不复制对象本身。新旧对象还是共享同一块内存,因此当color1更改了之后,color2也会跟着改变。

    针对引用类型的拷贝

    由上述可知,引用类型复制的是指针,那么如何切断两者之间的关系呢?可以拷贝一份它的数据,根据拷贝的层级又分浅拷贝和深拷贝。

    浅拷贝:

    • 浅拷贝只拷贝一层
    // 浅拷贝
    function shallowClone(source) {
        var target = {}
        for (var i in source) {
            if (source.hasOwnProperty(i)) {
                target[i] = source[i]
            }
        }
        return target
    }
    
    var a1 = {b: {c: {d: 1}}}
    var a2 = shallowClone(a1)
    a1.b.c = 4
    console.log(a1)  // { b: { c: 4 } }
    console.log(a2)  // { b: { c: 4 } }
    
    • ES6 的 Object.assign()
    • ES7 的...解构运算符

    深拷贝:深拷贝就是能够实现真正意义上的数组和对象的拷贝。递归调用"浅拷贝"。(深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象)

    深拷贝的方式:
    • JSON.parse(JSON.stringify(src)):这种方法有局限性,如果属性值是函数或者一个类的实例的时候,无法正确拷贝
    const liLei = {
        name: 'lilei',
        age: 28,
        habits: ['coding', 'hiking', 'running']
    }
    const liLeiStr = JSON.stringify(liLei)
    const liLeiCopy = JSON.parse(liLeiStr)
    liLeiCopy.habits.splice(0, 1) 
    console.log('李雷副本的habits数组是', liLeiCopy.habits)
    console.log('李雷的habits数组是',  liLei.habits)
    
    • 采用递归的方式
    function deepClone(obj) {
        if (typeof obj !== 'object' || obj === null) { // 基本类型本身就是深拷贝
            return obj
        }
    
        // 定义结果对象
        let copy = {}
    
        // 定义结果数组
        if (obj.constructor === Array) {
            copy = []
        }
    
        // 遍历对象的Key
        for (let key in obj) {
            console.log('key', key)
            // 如果key是对象的自有属性
            if(obj.hasOwnProperty(key)) {
                // 递归调用深拷贝方法
                copy[key] = deepClone(obj[key])
            }
        }
        return copy
    }
    
    const obj = {
        a: 1,
        b: 2,
        c: 3
    }
    
    var a1 = {b: {c: {d: 1}}}
    var a2 = deepClone(a1)
    a1.b.c = 4
    console.log(a1)  // { b: { c: 4 } }
    console.log(a2)  // { b: { c: { d: 1 } } }
    

    采用递归的方式调用深拷贝方法,若属性为值类型,则直接返回;若属性为引用类型,则递归遍历。

    • 借助第三方库

      • lodash 的cloneDeep(src)

      • jq 的extend(true, result, src1, src2[ ,src3])

  • 相关阅读:
    Ext.Ajax.request 传值问题
    类型反射与晚期绑定
    .net使用外部程序集拓展功能
    C#求解哈夫曼树
    几种获取操作系统语言的方法及其相似点与不同点
    C#调用非托管代码(C++方法)的2种方式
    构建可终结类型和可处置类型
    dockercompose 安装配置neo4j
    Windows 7 SDK Fails to Install with Return Code 5100 (GRMSDK_EN_DVD.iso)
    mysql密码修改方法
  • 原文地址:https://www.cnblogs.com/zppsakura/p/14202160.html
Copyright © 2011-2022 走看看