深拷贝的五种实现方式

一、数据类型

基本数据类型(String,Number,Boolean,null,Undefined):直接存储在栈(stack)中的数据

(object):存储时会在栈内存存储引用(堆内存中存值的地址),堆内存存储真正的值,栈内存中的引用指向堆内存的值。

二、浅拷贝与深拷贝

浅拷贝:当把一个对象赋值给一个新的变量时,复制的其实是该对象的在栈中的引用地址(指向某个对象的指针),而不是对象值本身,新旧对象指向堆内存中同一片地址空间,共享同一块堆内存,无论哪个对象发生变化,其实都是改变的内存空间的内容,因此,两个对象是联动的

深拷贝:在堆内存中重新开辟一块空间,存放原对象的值,让栈中的引用指向这块新的内存地址,新旧对象不在相互影响

三、实现深拷贝的方式

1. 递归函数调用

const deepClone = (source) => {
    if (!source && typeof source !== object) {
        throw new Error(error arguments, deepClone)
    }
    const targetObj = source.constructor === Array ? [] : {}
    Object.keys(source).forEach(keys => {
        if (source[keys] && typeof source[keys] === object) {
            targetObj[keys] = deepClone(source[keys])
        } else {
            targetObj[keys] = source[keys]
        }
    })
    return targetObj
}

2. JSON.stringify + JSON.parse

const obj = {
    name: dd,
    age: 18,
    say: {
        text: hello
    }
}
const str = JSON.stringify(obj)
let obj2 = JSON.parse(str)
obj2.say.text = hi
console.log(obj); //{ name: dd, age: 18, say: { text: hello } }
console.log(obj2); //{ name: dd, age: 18, say: { text: hi } }

注意:JSON.string实现深拷贝有几个特点:

const obj3 = {
            func: function () { console.log(1) },
            obj: { name: h },
            arr: [1, 2, 3],
            und: undefined,
            ref: /^123$/,
            date: new Date(),
            NaN: NaN,
            infinity: Infinity,
            sym: Symbol(1)
        }

        console.log(JSON.parse(JSON.stringify(obj3)))
        // NaN: null
        // arr: (3) [1, 2, 3]
        // date: "2023-02-07T10:27:29.165Z"
        // infinity: null
        // obj: {name: h}
        // ref: {}
拷贝的对象的值如果有函数,undefined,symbol 这几种类型,经过 JSON.stringify 序列化后字符串中这个键值对会消失。 拷贝 Date 类型会变成字符串 无法拷贝不可枚举的属性 无法拷贝对象原型链 拷贝 RegExp 引用类型会变成空对象 对象中含有 NaN、infinity 以及 -infinity,JSON 序列化后的结果变成 null

3. lodash (js库)

const _ = require(lodash)
        const foo = {
            name: 张三,
            info: {
                age: 24
            }
        }
        const newFoo = _.cloneDeep(foo);
        foo.info.age = 25
        console.log(foo, newFoo) // { name: 张三, info: { age: 25 } } { name: 张三, info: { age: 24 } }

4. Object.assign

注意:只有当对象中没有嵌套对象时,才可以实现深拷贝
const foo = {
    name: 张三,
    age: 24
}
const newFoo = Object.assign({}, foo)
foo.age = 25
console.log(foo, newFoo) // {name: 张三, age: 25} {name: 张三, age: 24}

// 对象中有内嵌的对象时
const foo = {
    name: 张三,
    info: {
        age: 24
    }
}
const newFoo = Object.assign({}, foo)
foo.info.age = 25
console.log(foo, newFoo) // { name: 张三, info: { age: 25 } } { name: 张三, info: { age: 25 } }

5.structuredClone

const foo = {
    name: 张三,
    info: {
        age: 24
    }
}
const newFoo = structuredClone(foo) // 
foo.info.age = 25
console.log(foo, newFoo) // { name: 张三, info: { age: 25 } } { name: 张三, info: { age: 24 } }
经验分享 程序员 微信小程序 职场和发展