阅读 702

JS:快速搞懂深浅拷贝,光速手写深拷贝

一、什么是深拷贝?什么是浅拷贝?

深拷贝:修改变量的值不会影响原先变量的值,一般情况下基本数据类型都是深拷贝

let num1 = 2 ;     //在内存中开辟了一块空间
let num2 = num1;   //在内容中又新开辟了一块空间
num2 = 666 ;       //num1依然是等于2
复制代码

在这个例子中,把num1的值赋值给num2,修改了num2的值是不会影响到num1的值,所以num2=666后原先的num1的值仍然是2

浅拷贝:修改变量的值会影响原先变量的值,一般情况下引用数据类型就是浅拷贝

class Person{
    name = '小明';
    age = 18;
    address = {
        city:'重庆',
        school:'重庆大学'
    }
    arr = [1,2,3]
}
let p1 = new Person()
let p2 = p1
p2.name = '小红'
p2.address.city = '上海'
p2.arr.push(4)
复制代码

在这个例子中,p1 new了一个Person,并且和p1建立相等关系,然后只在p2里面修改了name,address,arr等属性的值,最后打印p1的时候我们会发现p1存的对象里面发生了改变

原因是p2和p1建立相等关系的时候,可以理解成p2存入了p1的地址值,而这个地址值指向的就是Person对象,所以我通过p2修改了对象里面的属性,然后通过p1去访问的时候,地址值没有发生变化,这两个p1和p2的地址都指向这个对象,所以通过p1访问到的对象已经被通过p2修改了

二、手写深拷贝

继续上面的例子,有的时候,我们想修改p2的值不影响到p1,其实可以直接一个一个的人为写入,大概就是这样的方式:

p2.name = p1.name
p2.age = p1.age
...
复制代码

其实这个方法是有局限的,如果p1里面的属性太多了,一个一个写实属太愚蠢了。

其次,当我们写到p2.address = p1.address的时候,又对对象进行了引用,这里又变成了浅拷贝了

所以我们可以通过手写一个 深拷贝函数 来解决我们的问题

function deepCopy( target , source ){       //source代表你想要被拷贝的元素 , target代表你想要拷贝的元素
    //1.for in 循环拿到 被拷贝元素 里面的属性
    for(let key in source){
        //2.拿到 被拷贝元素 里面的属性的值
        let sourceValue = source[key]
        //3.拿到遍历到的属性值的时候,需要判断这个属性值是不是引用类型
        if(sourceValue instanceof Object){
            //3.1如果是引用类型,做以下处理
            let subTarget = new sourceValue.constructor  
            /**
            *这里说一下:引用类型都会有一个constructor属性,数组的constructor会返回Array,对象的constructor会返回Object
            *所以new sourceValue.constructor 就省去了判断它是数组还是对象
            */
            target[key] = subTarget
            //递归
            deepCopy(subTarget,sourceValue)
        }else{
                //3.2如果不是引用类型,直接赋值就完事了
                target[key] = sourceValue
        }
    }
}
复制代码

这个函数读者们可以多琢磨一下,特别是里面的递归

一旦看懂,随便手写

文章分类
前端
文章标签