JS中浅拷贝和深拷贝的几种实现方式

概念

    深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象。它们最根本的区别在于是否真正获取了一个对象的复制实体,而不是引用。简单来说,假设B复制了A,当修改B时,看A是否会发生变化,如果A变了,说明是浅拷贝;如果A没变,那就是深拷贝

浅拷贝

1. 用 = 号赋值引用地址
let obj = {
    name: '李四',
    age: 20,
    sex: '男',
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    school: {
		colleges: "野鸡烧烤工程系"
		grade: 2020
		name: '野鸡大学'
		stuNo: 2020123456
	},
    say: () => {
        console.log('哇塞')
    }
};

let obj2 = obj;

obj2.name = 'Rose';
obj2.sex = '女';
obj2.school.name = '野鸡变凤凰';

console.log('obj', obj);
console.log('obj2', obj2);
2. for…in

    被循环的对象存在嵌套对象时为浅拷贝

let obj = {
    name: '李四',
    age: 20,
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    school: {
        name: '野鸡大学',
        grade: 2020,
        stuNo: 2020123456,
        colleges: '野鸡烧烤工程系',
    },
    say: () => {
        console.log('哇塞')
    }
};

let obj2 = {};
for (let key in obj) {
    obj2[key] = obj[key];
}

obj2.name = '小六';
obj2.sex = '男';
obj2.school.name = '野鸡变凤凰';

console.log('obj', obj);
console.log('obj2', obj2);
3. Object.assign()

    ① Object.assign()只有源对象,没有目标对象时为浅拷贝

let obj = {
    name: '李四',
    age: 20,
    sex: null,
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    school: {
        name: '野鸡大学',
        grade: 2020,
        stuNo: 2020123456,
        colleges: '野鸡烧烤工程系',
    },
    say: () => {
        console.log('哇塞')
    }
};

let obj2 = Object.assign(obj);

obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';

console.log('obj', obj);
console.log('obj2', obj2);

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

let obj = {
    name: '李四',
    age: 20,
    sex: null,
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    school: {
        name: '野鸡大学',
        grade: 2020,
        stuNo: 2020123456,
        colleges: '野鸡烧烤工程系',
    },
    say: () => {
        console.log('哇塞')
    }
};
let obj2 = {
    name: '小二',
    school: {
        name: '凤凰大学'
    }
};

Object.assign(obj2, obj);

obj2.name = '小六';
obj2.school.name = '野鸡变凤凰';

console.log('obj', obj);
console.log('obj2', obj2);

深拷贝

1. JSON.parse(JSON.stringify())
let obj = {
    name: '李四',
    age: 20,
    sex: null,
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    school: {
        name: '野鸡大学',
        grade: 2020,
        stuNo: 2020123456,
        colleges: '野鸡烧烤工程系',
    },
    say: () => {
        console.log('哇塞')
    }
};
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.name = '小六';
obj2.school.name = '野鸡变凤凰';

console.log(obj);
console.log(obj2);

    注意:这种方式无法拷贝 正则表达式,undefine,function

2. for…in

    被循环的对象不存在嵌套对象时为深拷贝

let obj = {
    name: '李四',
    age: 20,
    sex: '男',
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    say: () => {
        console.log('哇塞')
    }
};

let obj2 = {};
for (let key in obj) {
    obj2[key] = obj[key];
}

obj2.name = 'Rose';
obj2.sex = '女';

console.log('obj', obj);
console.log('obj2', obj2);
3. Object.assign()

    Object.assign() 方法只复制源对象中可枚举的属性和对象自身的属性。如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖

let obj = {
    name: '李四',
    age: 20,
    sex: null,
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    say: () => {
        console.log('哇塞')
    }
};
let obj2 = {
    name: '小二',
};

Object.assign(obj2, obj);
obj2.name = '小六';

console.log('obj', obj);
console.log('obj2', obj2);
4. 递归

    递归拷贝所有层级属性

let obj = {
    name: '李四',
    age: 20,
    sex: null,
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    school: {
        name: '野鸡大学',
        grade: 2020,
        stuNo: 2020123456,
        colleges: '野鸡烧烤工程系',
    },
    say: () => {
        console.log('哇塞')
    }
}
function deepClone(obj) {
    let objClone = Array.isArray(obj) ? [] : {};
    if(obj && typeof obj === 'object' ) {
        for(key in obj) {
            if(obj.hasOwnProperty(key)){
                // 判断 obj 子元素是否为对象,如果是则递归复制
                if(obj[key] && typeof obj[key] === 'object') {
                    objClone[key] = deepClone(obj[key]);
                } else {
                    // 如果不是则直接复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}
let obj2 = deepClone(obj);

obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';

console.log('obj', obj);
console.log('obj2', obj2);
5. $.extend()

    通过 jQuery 的 extend() 方法实现深拷贝,第一个参数 true 为深拷贝,false 为浅拷贝

let obj = {
    name: '李四',
    age: 20,
    sex: null,
    tel: /^1[345789]\d{9}$/,
    address: undefined,
    flag: true,
    school: {
        name: '野鸡大学',
        grade: 2020,
        stuNo: 2020123456,
        colleges: '野鸡烧烤工程系',
    },
    say: () => {
        console.log('哇塞')
    }
}

var obj2 = $.extend(true, {}, obj); // true 为深拷贝,false 为浅拷贝

obj2.name = 'Rose';
obj2.school.name = '野鸡变凤凰';

console.log('obj', obj);
console.log('obj2', obj2);
6. slice()

    slice() 对数组进行深拷贝

let arr = [1, 2, 3, 4, 5, 6];

let arr2 = arr.slice(0);

arr2[0] = 'Rose';
arr2[1] = '女';

console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]
7. concat()

    concat() 对数组进行深拷贝

let arr = [1, 2, 3, 4, 5, 6];

let arr2 = arr.concat();

arr2[0] = 'Rose';
arr2[1] = '女';

console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]
  • 14
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 21
    评论
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半度℃温热

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值