字面意思解释
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.递归方法可以完美实现深拷贝