深拷贝和浅拷贝的区别?怎么实现深拷贝?

Posted by CodingWithAlice on July 11, 2019

深拷贝和浅拷贝的区别?怎么实现深拷贝?

浅拷贝:只复制一层对象的属性【扩展运算符{...obj}Object.assign({}, obj)

​ 数组的浅拷贝:Array.from(arr)[…arr]arr.concat()arr.slice()

深拷贝 :会递归地复制对象的所有层级的属性【递归函数、Json.parse(Json.stringify(obj))

​ Json.parse(Json.stringify(obj)) 局限:不能复制函数、循环引用

区别

  • 对象的属性是基本类型时:深拷贝和浅拷贝都是拷贝一个副本,拷贝后修改新对象不会影响原始对象;

  • 对象的属性是引用类型时:浅拷贝只拷贝内存地址,不拷贝引用地址指向的数据 - 修改新对象会影响原始对象;深拷贝则会拷贝数据,修改新对象不会影响原始对象;

浅拷贝的实现

1.Object.assign():把任意多个的源对象自身的 可枚举属性 拷贝给目标对象,然后返回目标对象

2.Array.prototype.concat():合并两个或多个数组,不传参数时相当于浅拷贝

let arr = [1, 2, {username: 'aQiu'}];
let arr2 = arr.concat();   
arr2[2].username = 'Alice';
console.log(arr); // [1, 2, {username: 'Alice'}] 变了

3.Array.prototype.slice(start, end):由 start 和 end 决定的数组的浅拷贝

深拷贝的实现
  1. JSON.parse(JSON.stringify()):用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,可以实现数组或对象深拷贝,但不能处理函数、循环引用
let arr = [1, 3, {username: 'aQiu'}];
let arr2 = JSON.parse(JSON.stringify(arr));
arr2[2].username = 'Alice'; 
console.log(arr); // [1, 3, {username: 'aQiu'}] 不变
  1. 递归:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
// 利用 for 循环可以简单实现为
function deepCopy(target) {
    // 判断对象是引用数据还是基础数据 - 基础数据直接返回
    if (typeof target !== 'object' || target === null) {
        return target
    }
    let copy;
    if (Array.isArray(target)) {
        copy = [];
        for (let i = 0; i < target.length; i++) {
            copy[i] = deepCopy(target[i]);
        }
    } else {
        copy = {};
        for (let key in target) {
            if (target.hasOwnProperty(key)) {
                copy[key] = deepCopy(target[key]);
            }
        }
    }
    return copy;
}
// 自己写的 - reduce 的问题在于 [[1,2,3],4,5,6] 数组嵌套数组时,被打平
// 数组
if (Array.isArray(target)) {
    return target.reduce((pre, cur) => {
        return pre.concat(deepCopy(cur))
    }, []);
} else {
    // 对象
    return Object.keys(target).reduce((pre, cur) => { 
        return Object.assign(pre, { [cur]: deepCopy(target[cur]) }) 
    }, {})