js深浅拷贝 - 详解

139 阅读2分钟

是什么:

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。

深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

为什么:

浅拷贝只解决了对象第一层拷贝的问题,如果接下去的值中还有对象的话,那么就又回到最开始的话题了,两者享有相同的地址。要解决这个问题,我们就得使用深拷贝。

怎么做:

浅拷贝

1 =

let a = {
    s: 'aaa'
}
let b = a;
console.log(b === a); // true

2 展开运算符 ... 

会拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是地址。

let a = {
    a: 'aaa',
    b: {
        a: 'aaa'
    }
}
let b = {
    ...a
};
console.log(b === a); // false
console.log(b.b === a.b); // true

3 Object.assign

Object.assign 只会拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是地址。

let a = {
    a: 'aaa',
    b: {
        c: 'ccc'
    }
}
let b = Object.assign({}, a);
console.log(b === a); // false //对比整个对象的话是深拷贝,因为会拷贝所有的属性值到新的对象中
console.log(b.b === a.b); // true //只对比对象属性值的话是浅拷贝

深拷贝

1 JSON.parse(JSON.stringify(object))

let a = {
    age: 1,
    jobs: {
        first: 'FE'
    }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

该方法也是有局限性的:

  • 会忽略 undefined
  • 会忽略 symbol
  • 不能序列化函数
  • 不能解决循环引用的对象 - 报错

2 js工具库 lodash 的深拷贝函数

安装:

浏览器环境:

<script src="lodash.js"></script>

通过 npm:

$ npm i --save lodash

使用:_.cloneDeep(value)

3 自做一个递归函数去深拷贝 - 还没能处理对象带函数的情况 - 不推荐

function deepClone(obj) { //可传入对象 或 数组
    //  判断是否为 null 或 undefined 直接返回该值即可,
    if (obj === null || !obj) return obj;
    // 判断 是要深拷贝 对象 还是 数组
    if (Object.prototype.toString.call(obj) === "[object Object]") { //对象字符串化的值会为 "[object Object]"
        let target = {}; //生成新的一个对象
        const keys = Object.keys(obj); //取出对象所有的key属性 返回数组 keys = [ ]
        //遍历复制值, 可用 for 循环代替性能较好
        keys.forEach(key => {
            if (obj[key] && typeof obj[key] === "object")
                //如果遇到的值又是 引用类型的 [ ] {} ,得继续深拷贝
                target[key] = deepClone(obj[key]); //递归
            else
                target[key] = obj[key]; // 仍旧是浅拷贝
        })
        return target //返回新的对象
    } else if (Array.isArray(obj)) {
        // 数组同理
        let arr = [];
        obj.forEach((item, index) => {
            if (item && typeof item === "object")
                arr[index] = deepClone(item);
            else
                arr[index] = item;
        })
        return arr
    }
}

const obj = {
    a: 1,
    b: {
        a: 2
    },
    c: function () {
        console.log('c');
    }
};
const obj2 = deepClone(obj);

console.log(obj === obj2); //false
console.log(obj.c === obj2.c); //true

遗留问题:如何深拷贝一个带函数的对象,貌似js没有提这个 - 回来解决

注意点:

序列化:js中的object转化为字符串

常用json.stringify

反序列化:json字符串转化为object

常用json.parse