深拷贝的五种实现方式

一、数据类型

基本数据类型(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 } }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

山楂树の

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

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

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

打赏作者

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

抵扣说明:

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

余额充值