0


前端 JS 浅拷贝与深拷贝

一、问题引出

基础类型的数据存放:

    let a = 100
    let b = a
    console.log("a:" + a, "b:" + b)
    a = 50
    console.log("a:" + a, "b:" + b)

打印:这里可以看到两个基础变量的值是互不影响的

这里a修改没有修改b的示意图如下:

基础类型的a和b都分别存放在栈内存里,当a被修改是b不会被影响。

下面我们将a和b换成对象类型:

    let a = [1, 2, 3]
    let b = a
    console.log("a:" + a, "b:" + b)
    a[0] = 100
    console.log("a:" + a, "b:" + b)

打印:可以看到,当a被修改是b也发生了改变。

此时的内存分配示意图如下:

由于对象是存在堆内存里的,当a赋值给b时,其实仅是b指向了a的同一个堆地址,当a修改此地址的对象时,b指向的对象就是该对象,所以会同步改变。

解决方案有两个,浅拷贝和深拷贝。

二、浅拷贝

1、通过解构重构实现浅拷贝
    let a = [1, 2, 3]
    let b = [...a]
    console.log("a:" + a, "b:" + b)
    a[0] = 100
    console.log("a:" + a, "b:" + b)

打印:此时,修改a并不会影响b的值。

此时的内存分配图如下:

通过以上方法,可以让b复制a的值重新生成一个新对象,在堆内存中重新开辟一个新的对象空间,此时,a和b的地址是不一样的。

你可能会说,这两个对象都完全独立开来了,怎么算浅拷贝呢,不应该是深拷贝吗?下面进一步实验:

    let a = [1, 2, 3, [4, 5]]
    let b = [...a]
    console.log(a)
    console.log(b)
    a[3][0] = 10
    console.log(a)
    console.log(b)

打印:可以看到当我实验二维数组时,二维数组里的内容被修改,还是会连同b一起修改.

此时的内存发布图如下:

浅拷贝只会拷贝最近一层的数据,二维数组为更进一层的数据,第一层存的只是第二层数据的地址,浅拷贝不会拷贝第二层以上的数据,这就是出现上述现象的原因。

如果此时a改的是第一项,不会堆b有任何影响,当a改的是共同指向的地址里的数据时,b的那部分数据也会随之改动。

三、深拷贝

对于二中提到的情况对于的深拷贝示意图如下:

下面我们将通过代码来实现深拷贝:

1、自定义实现深拷贝

实现深拷贝的函数:

    function deepClone(oldData) {
        if (typeof oldData === "object" && oldData !== null) {
            let res = Array.isArray(oldData) ? [] : {};
            for (let k in oldData) {
                if (oldData.hasOwnProperty(k)) {
                    res[k] = deepClone(oldData[k])
                }
            }
            return res
        } else {
            return oldData
        }
    }

拷贝执行:

    let obj = {
        name: "Jack",
        age: 18,
        hobby: ["swimming", "jogging"],
        fn() {
            console.log(this.name)
        }
    }

    let obj2 = deepClone(obj)
    console.log(obj2)
    obj.hobby[0] = "play"
    obj.fn = function () {
        console.log("obj:" + this.age)
    }
    console.log(obj)
    console.log(obj2)
    obj.fn()
    obj2.fn()

打印:可以看到深拷贝成功了,函数也深拷贝成功了。

2、JSON实现深拷贝

网上有很多说可以实验JSON的序列化与反序列化实现深拷贝,但这样做其实是有缺点的,JSON的序列化与反序列化并不能拷贝函数类型

    let obj = {
        name: "Jack",
        age: 18,
        hobby: ["swimming", "jogging"],
        fn() {
            console.log(this.name)
        }
    }

    let obj3=JSON.parse(JSON.stringify(obj))
    console.log(obj3)

打印:可以看到序列拷贝的并没有函数对象

四、总结

1、如果是基本数据类型,js都是采用深拷贝的,数据之间不会有任何影响;

2、可以通过解构重构或Object.assgin方法来实现浅拷贝;

3、深拷贝可以使用实验中的深拷贝递归函数来实现,对于一些没有函数的对象可以实验JSON.parse(JSON.stringify()) 的方法来快速实现深拷贝。

总结到此!


本文转载自: https://blog.csdn.net/qq_50909707/article/details/143858508
版权归原作者 Dragon Wu 所有, 如有侵权,请联系我们删除。

“前端 JS 浅拷贝与深拷贝”的评论:

还没有评论