js 浅拷贝与深拷贝

js 有两种数据类型,基础数据类型和引用数据类型;基础数据类型都是按值访问的,我们可以直接操作保存在变量中的实际的值。而引用类型如Array,

我们不能直接操作对象的堆内存空间。引用类型的值都是按引用访问的,即保存在变量对象中的一个地址,该地址与堆内存的实际值相关联。

 1.浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存;

 浅拷贝是指只复制一层对象,当对象的属性是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化

案例:

// 引用类型
        let obj1 = { a: 10, b: 20, c: 30 };
        let obj2 = obj1;
        obj1.b = 60;
        // 或
        // obj2.b = 50;
        console.log(obj1);
        console.log(obj2);

        let array1 = [0, 1, 2, 3, 4];
        let array2 = array1;
        console.log(array1 === array2);
        array1[0] = 1;
        console.log(array1, array2);

2.深拷贝:复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。

基础数据类型

 let a = 'zjl';
        let b = a;
        a = 'zmf';
        // 或
        // b='dwb';
        console.log('a:' + a + '   ' + 'b:' + b);

所以当你此时修改a='zmf',对b并不会造成影响,因为此时的b已自食其力,不受a的影响了。当然,let a='zjl',b=a;虽然b不受a影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。

 // 这里再次强调,深拷贝,是拷贝对象各个层级的属性,可以看个例子。JQ里有一个extend方法也可以拷贝对象,我们来看看
        let array3 = [1, 3, 4, 2, 5];
        let array4 = array3.slice();
        array3[0] = 10;
        array4[0] = 20;
        console.log(array3, array4);
        // 那是不是说slice方法也是深拷贝了,毕竟array4也没受array3的影响,上面说了,深拷贝是会拷贝所有层级的属性,还是这个例子,我们把array3改改
        let array5 = [1, 3, 5, 2, [2, 3], 4, 5];
        let array6 = array5.slice();
        array5[4][0] = 4;
        // array6[4][0]=5;
        console.log(array5, array6);
        // 拷贝的不彻底啊,array6对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了array5的控制,说明slice根本不是真正的深拷贝。

下面就来说说深拷贝的一些方法

1.递归

看这个之前可以去看看递归算法

 let json1 = { "name": "shauna", "age": 18, "arr1": [1, 2, 3, 4, 5], "string": 'got7', "arr2": [1, 2, 3, 4, 5], "arr3": [{ "name1": "shauna" }, { "job": "web" }] };
        let json2 = {};
        function copy(obj1, obj22) {
            let obj2 = obj22 || {};
            for (let name in obj1) {
                // console.log(obj1[name])
                if (typeof obj1[name] === "object") {
                    obj22[name] = (obj1[name].constructor === Array) ? [] : {};
                    copy(obj1[name], obj22[name]);
                } else {
                    obj22[name] = obj1[name];
                }
            }
            return obj22;
        }
        json2 = copy(json1, json2);
        json1.arr1.push(6);
        console.log(json1.arr1, json2.arr1);

        // 1.2
        function deepClone(obj3) {
            let objClone = Array.isArray(obj3) ? [] : {};
            if (obj3 && typeof obj3 === "object") {
                for (key in obj3) {
                    if (obj3.hasOwnProperty(key)) {
                        //判断ojb子元素是否为对象,如果是,递归复制
                        if (obj3[key] && typeof obj3[key] === "object") {
                            objClone[key] = deepClone(obj3[key]);
                        } else {
                            //如果不是,简单复制
                            objClone[key] = obj3[key];
                        }
                    }
                }
            }
            return objClone;
        }
        let obja = [1, 2, 3, 4],
            objb = deepClone(obja);
        obja[0] = 2;
        console.log(obja, objb);

2.JSON对象的parse和stringify 但这种方法的缺陷是会破坏原型链,并且无法拷贝属性值为function的属性

function JsonCopy(objj) {
            let _objj = JSON.stringify(objj);
            _objj = JSON.parse(_objj)
            return _objj;
        }
        let jsona = [0, 1, [2, 3], { function() { console.log(false) } }, 4]; //这里加了function这个对象,这个对象不能被拷贝过去

        let jsonb = JsonCopy(jsona);
        jsona[2][1] = 6;
        jsonb[2][1] = 7;
        console.log(jsona, jsonb);

3.es6 Object.assign():Object.assign()是一种可以对非嵌套对象进行深拷贝的方法,如果对象中出现嵌套情况,那么其对被嵌套对象的行为就成了普通的浅拷贝。

let zjl = {
            a: 1,
            b: 2,
            c: {
                d: 1,
            }
        }
        let zmf = {};
        Object.assign(zmf, zjl);
        zjl.a++;
        zjl.a === 2 //true
        zmf.a === 1 //true
        zjl.c.d++;
        zjl.c.d === 2 //true
        zmf.c.d === 1 //false
        zmf.c.d === 2 //true

 4.JQ的extend方法

 $.extend([deep], target, object1[, objectN])

 deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝

target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。

 object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。

let jqa = [0, 1, [2, 3], 4],

jqb = $.extend(true, [], jqa);

 jqa[0] = 1;

 jqa[2][0] = 1;

console.log(a, b);

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值