简述JavaScirpt复杂(引用)数据类型的深浅拷贝

    //  拷贝:  

    //  ------简单数据类型拷贝:  不存在深浅拷贝。     值在栈中------------直接传值;       例:var a=10;---var b=a 

    // (1)浅拷贝:针对复杂(引用)数据类型,拷贝到栈中的值; 

    // ------(数组/对象)浅拷贝      地址在栈中------------传地址;     例:var obj1={id:123};---var obj2=obj1(obj1和obj2在栈中拷贝了得到了相同的地址,指向同一份堆中的数据)。

    // (2) 深拷贝:针对复杂(引用)数据类型(数组/对象),拷贝堆中的值给新的数组/对象;------复杂数据类型拷贝堆中的值为深拷贝。

    // 总结特点
    // (1)浅拷贝特点                         拷贝的时候只是拷贝了一份引用,修改拷贝以后的数据会影响原来的数据。

    // (2)深拷贝(对象/数组)特点:           拷贝的时候会从堆拷贝一份新的数据,修改拷贝得到的副本的数据不会改变原数据。


    //(数组/对象)浅/深拷贝方法:


    // 1、数组的拷贝

    // 1) 采用扩展运算符
    var arr1 = [1, 2, 3, 4];
    var arr2 = [...arr1];

    arr1[0] = 666;
    console.log(arr1); // [666, 2, 3, 4]
    console.log(arr2); // [1, 2, 3, 4]

    // 2) 数组方法Array.slice()---------Array.slice(开始的索引,结束的索引)并不会修改数组,而是返回一个包含开始索引到结束索引"之前"的子数组,字符串也有slice()方法,用法一致。
    var arr1 = [1, 2, 3, 4];
    arr2 = arr1.slice(0)

    arr1[0] = 666;
    console.log(arr1); // [666, 2, 3, 4]
    console.log(arr2); // [1, 2, 3, 4]

    // 3) 数组方法Array.contact()---------Array.contact(数组1,数组2.../数组元素1,元素2...)并不会修改数组,而是返回一个包含的子数组,字符串也有slice()方法,用法一致。
    var arr1 = [1, 2, 3, 4];
    arr2 = arr1.concat()

    arr1[0] = 666;
    console.log(arr1); // [666, 2, 3, 4]
    console.log(arr2); // [1, 2, 3, 4]


    // 2、对象的拷贝
    // 1) Object.assign(obj) 拷贝:当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。 ————————————————————Object.assign(target, ...sources);
    var obj = {
        name: 'zs', // 一级属性
        brother: {
            name: 'ls', // 二级属性
            friend: {
                name: 'ww' // 多级属性
            }
        }
    }
    var obj1 = Object.assign(obj);
    console.log(obj1);


    // 2) 封装函数拷贝:通过for(var k in obj)遍历对象,将简单数据类型实现赋值拷贝,通过条件判断数据类型,结合函数递归实现深层拷贝,从而达到深拷贝。
    //    !!! 通过判断数据类型,可以实现不管数组/对象都能统统(深)拷贝

    // 方法1.遍历方法1(和方法2一致,封装函数而已)
    function deepClone(target) {
        let result
        if (typeof target === 'object') {
            if (Array.isArray(target)) {
                result = []
                for (let i in target) {
                    result.push(deepClone(target[i]))
                }
            } else if (target === null) {
                result = target
            } else if (target.constructor === RegExp) {
                result = target
            } else if (target.constructor === Date) {
                result = target
            } else {
                result = {}
                for (let i in target) {
                    result[i] = deepClone(targer[i])
                }
            }
        } else if (typeof target === 'function') {
            // 如果是函数
            result = new Function('return ' + target.toString())
        } else {
            // 如果是基本数据类型,如number、string、boolean、undefined
            result = target
        }
        return result
    }
    // 法2:遍历方法2
    function deepCopy(newObj, oldObj) {
        for (var k in oldObj) {
            // 判断我们的属性属于那种数据类型
            // 1. 获取属性值  oldObj[k]
            var item = oldObj[k];
            // 2. 判断这个值是否是数组
            if (item instanceof Array) {
                newObj[k] = [];
                deepCopy(newObj[k], item);
            } else if (item instanceof Object) {
                // 3. 判断这个值是否是对象
                newObj[k] = {};
                deepCopy(newObj[k], item);
            } else {
                // 4. 属于简单数据类型
                newObj[k] = item;
            }
        }
        return newObj
    }
    // 方法3  通过转成JSON字符串再转回来(序列化--反序列化),前提是:要转化的对象符合**json数据类型**的格式:函数不行。
    //深拷贝
    function deepClone(data) {
        let newData = JSON.stringify(data),
            dataClone = JSON.parse(newData);
        return dataClone;
    };
    //测试
    let arr = [1, 2, 3],
        newData = deepClone(arr);
    arr[0] = 2;
    console.log(arr, newData) //[2,2,3]  [1,2,3]
                                                  ---------------2021.06.03发布于掘金  Qiang
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享