【每天一个前端小知识】-js深浅拷贝

188 阅读4分钟

字面意思解释

1、什么是拷贝

拷贝是一个音译词,译自英文copy,拼音是kǎo bèi。我们常说的克隆、复制,在js代码世界里,我们可以理解为一种意思,我下面写了两个小案例,都是拷贝的代码实现

//案例1 基本数据类型拷贝
var num = 1;
var num2 = num

//案例2 引用数据类型拷贝
var obj1 = {
    name:'张三',
    age:18,
}
var obj2 = obj1

上面就是一个简单的拷贝

2、什么是浅拷贝

我们先来分析上面的案例1

//案例1 基本数据类型拷贝
var num = 1;
var num2 = num
num2 = 2
console.log(num1)//结果是1
console.log(num2)//结果是2

可以看到num2发生了改变之后并没有影响到num1

再来看案例2

//案例2 引用数据类型拷贝
var obj1 = {
    name:'张三',
    age:18,
}
var obj2 = obj1
obj2.age = 19
console.log(obj1.age)
结果是 19
console.log(obj2.age)
结果是 19

可以看到obj2的age改成了19之后,obj1的age也变成了19

我们发现案例1中的基本数据类型,只用了一个简单的“=”号就可以做到改变其中一个的值而另一个不受影响,所以得出结论:js的5种基本数据类型:String,Number,Boolean,Null,undefined是不存在深拷贝和浅拷贝之分的,所以我们所说的深浅拷贝都是基于引用数据类型而言的

那么引用数据类型:Object及里面包含的function、Array、Date等就存在深浅拷贝之分

我们上面的案例2,就是一个浅拷贝

浅拷贝的定义:只复制了对象的引用,并没有复制对象真正的值,所以当对象的值发生改变时,obj1和obj2指向的都是同一个空间,所以他们都发生了改变

3、什么是深拷贝

先来看上面的案例

//案例2 引用数据类型拷贝
var obj1 = {
    name:'张三',
    age:18,
}
var obj2 = obj1
obj2.age = 19
console.log(obj1.age)
console.log(obj2.age)

如果能够实现:obj2对于obj1的拷贝之后,obj2无论发生任何改变,都不会影响到obj1,

输出的结果是18 和 19,那么我们就实现了初衷,这就是深拷贝。

深拷贝的定义:深拷贝就是对目标的完全拷贝,不止是复制了一层引用,就连值也复制了,只要进行了深拷贝,它们老死不相往来,谁也不会影响谁

如何实现深拷贝

1、利用 JSON 对象中的 parse 和 stringify

var array1 = [1,2,3,4,5];
var array2 = JSON.parse(JSON.stringify(array1 ));console.log(array1 === array2); //false
var obj1 = {
    name:'张三',
    age:18,
    car:['现代','大众'],
    home:{
        address1:'北京',
        address2:'上海'
    }
}
var obj2 = JSON.parse(JSON.stringify(obj1));

obj2.car = ['奔驰','宝马'];
obj2.home.address1 = '华盛顿';

console.log(obj1);
//{name:'张三',age:18,car:['现代','大众'],home:{address1:'北京',address2:'上海'}}

console.log(obj2);
//{name:'张三',age:18,car:['奔驰','宝马'],home:{address1:'华盛顿',address2:'上海'}}

遇到对象中包含函数时

var obj1 = {
    name:'张三,
    car:['现代','宝马'],
    sayHello:function(){
        console.log("你好")
    }
}
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2)
//{name:'张三',age:18,car:['现代','宝马']}

这时,我们发现obj1中的function并没有拷贝过来,所以JSON.parse(JSON.stringify())这种方法如果遇到对象中包含function时,就无法实现拷贝

2、递归实现深拷贝

//创建一个递归函数         function deepClone(source){            //判断复制的目标是数组还是对象            const targetObj = source.constructor === Array ? [] : {};            //遍历目标            for (let keys in source) {                if(source.hasOwnProperty(keys)){                    //判断如果当前值是对象                    if(source[keys] && typeof source[keys] === 'object'){                        //判断当前的值是数组还说对象,并且声明一个相应的targetObj                        targetObj[keys] = source[keys].constructor === Array ? [] :{};                        //递归当前这个对象,把返回值传给targetObj[keys]                        targetObj[keys] = deepClone(source[keys])                    }else{                        //如果是值,直接赋值                        targetObj[keys] = source[keys]                    }                }            }            return targetObj;        }

试试带有函数的

        const oldObj = {            name:'张三',            sayHelle:function(){                console.log("hello word")            }        }        const newObj = deepClone(oldObj)        console.log(oldObj)        console.log(newObj)
//{name: "张三", sayHelle: ƒ}

可以的,由此可见递归的方式可以实现深拷贝

总结

1.基本数据类型没有深浅拷贝之分,只有引用数据类型才有

2.赋值运算符实现的是浅拷贝,只拷贝对象的引用值

3.JSON.parse(JSON.stringify())可以实现对象中不带有函数的深拷贝

4.递归方法可以完美实现深拷贝