JS中的深克隆(深拷贝)和浅克隆(浅拷贝)

330 阅读3分钟
js的两大数据类型:
  • 简单类型值:数值(Number)、字符串(String)、布尔值(Boolean)、null、undefined
  • 引用类型值:函数、数组
对象克隆的使用场景

1.将对象作为函数参数的时候,不希望操作原对象

2.面试常见问题

克隆的定义:

在js中对象克隆就是把对象值重新赋给一个新对象,克隆分为深克隆和浅克隆。

浅克隆

浅克隆:只是复制对象的第一级属性值,如果对象的第一级属性中包含引用类型,则只复制地址

简单数据类型浅克隆:

     //数值
        let num = 10;
        let num1 = num;
        num = 20;
        console.log(num);  //20
        console.log(num1); // 10
    //字符串
        let str = "hello";
        let str1 = str;
        str = "world";
        console.log(str); //world
        console.log(str1); // hello 

引用类型的浅克隆(错误示例):

        //错误示范
        const stu = {
            name:"张三",
            age:15,
        }
​
        const stu1 = stu;
​
        stu.name = "李四"
        console.log(stu); //李四
        console.log(stu1); //李四

为什么不行了呢?

引用类型的值都会被保存在堆内存中,在栈内存中会存在一个指针指向堆内存中的值。两个对象都指向一个地址,所以当地址一但改变,两个指向同一个地址所以都会改变

接下来了解一下for in语句

for in 语句

语句用于循环对象属性。

循环中的代码每执行一次,就会对数组的元素或者对象的属性进行一次操作

       let stu = {
            name:"yhl",
            age:18
        }
         
        for(let a in stu){
            console.log(a);// 可以获取到stu对象的属性 
            console.log(stu[a]);  //可以获取到属性值
        }

引用数据类型:第一种:使用 for in 语句进行对象的浅克隆

         // 浅拷贝
         let stu = {
            name:"张三",
            age:18
        }
        function copyObj(obj){
            let newObj = {};
            for(let i in obj){
                newObj[i] = obj[i]
            };
            return newObj;
        };
        let stu2 = copyObj(stu);
        stu.age = 20;
        console.log(stu); // {name:"张三",age:20}
        console.log(stu2); // {name:"张三",age:18}

第二种: 使用es6扩展运运算符

   const stu = {
        name:"张三",
        age:18
    }
    const stu1 = {...stu};
    stu.name = "李四"
    console.log(stu); // {name: '李四', age: 18}
    console.log(stu1);// {name: '张三', age: 18}

如果一个对象里面又嵌套一个对象呢?

     // 如果张三有个同学叫李四
        const stu = {
            name: "张三",
            age: 19,
            bestfriend: {
                name: "李四",
                age: 20
            }
        }
​
        function fun(stu) {
            let newStu = {};
            for (let i in stu) {
                
                newStu[i] = stu[i]
            }
            return newStu;
        }
        let newStu = fun(stu)
        stu.bestfriend.name = "王五"
        console.log(stu);   
        console.log(newStu);

image-20220404172833784.png

发现两种方法都会是对象里面的引用类型李四变成了王五,说明了浅克隆只会复制第一级属性,如果是包含了引用类型,就只复制地址。如果属性还有引用类型的话,就要使用深克隆了。

深克隆:

所有属性都会克隆,就算有引用地址也会进行克隆

第一种: JSON.parse和 JSON.stringify()实现克隆

 const stu = {
            name: "张三",
            age: 19,
            bestfriend: {
                name: "李四",
                age: 20
            }
        };
        let a = JSON.stringify(stu);
        console.log(a);
        let stu2 = JSON.parse(a);
        stu.bestfriend.name = "王五"
        console.log(stu);
        console.log(stu2);

运行结果: image-20220404181520055.png

第二种:递归调用

  const stu = {
            name: "张三",
            age: 19,
            bestfriend: {
                name: "李四",
                age: 20
            }
        };
​
        function fun(stu) {
            // 创建一个新对象
            let newStu = {};
            for (let i in stu) {
                // 克隆 
                if (stu[i] instanceof Object) {
                    newStu[i] = fun(stu[i])
                } else {
                    newStu[i] = stu[i]
                }
            }
            return newStu;
        }
        let newStu = fun(stu)
        stu.bestfriend.name = "王五"
        console.log(stu);
        console.log(newStu);
​
//运行结果和上图一样
深克隆和浅克隆的区别

浅度克隆:原始类型为值传递,对象类型仍为引用传递。其本质上并没有成为一个单独的个体与原对象脱离。

深度克隆:所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中。

以上就是我对深、浅克隆的理解,有理解不到位的地方欢迎大家指正!