这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
js克隆分为深克隆和浅克隆,可以直接复制的是浅克隆,不可以直接复制的是深克隆。
一、浅克隆
表示直接赋值后,再修改原数据,新对象不会产生变化,就是浅克隆,例如基本类型中String,Number,float,boolean等,可以直接赋值后也不会变化。
//例如
let a = '123';
let a1 = 'hi cl'
let b = a;
let b1 = a1;
console.log(b);//'123'
console.log(b1);'hi cl'
一、深克隆
克隆对象是引用类型,直接复制可能会丢失值,所以不能直接复制,这就要用到深克隆,不然在开发过程中会产生很多问题。
let a = [1,2,3];
let b = a;
a.pop();
console.log(a);//[1,2]
console.log(b);//[1,2]
这里示例的a修改后b也跟着修改了,引用类型是通过地址的方式赋值,说明a和b指向的是同一个地址,导致他们其中一个修改后另一个也修改了,下面说几种修改方式:
1、使用**JSON.stringify()**把js对象序列化(JSON字符串),再使用JSON.parse来反序列化,还原parse过的对象。
let cloneObj = JSON.parse(JSON.stringify(oldObj));//常用的克隆方式
缺点:
1)不能实现函数,正则,时间之类的克隆,如果对象里有时间或者正则之类的,例如时间类型的字符被JSON.parse后就会是字符串形式,而不是时间对象。
2)会丢失对象的constructor,所有的构造函数会指向Object
3)对象有循环引用,会产生报错。
4)对象中有undefined,symbol的类型的对象,序列化后结果会把undefined丢失,NaN,Infinity序列化后结果会变成null。
2、使用**object.assign()**用于将所有可枚举属性的值从一个或者多个源对象分配到目标对象,然后然会目标对象。
const newObj = Object.assign([],oldObj);
缺点:
只对顶层对象保留了赋值,没有递归向下兼容对下面的属性进行深拷贝,所以下面的对象还是浅拷贝,没有要求的可以使用。
3、使用递归的方式,创建一个新对象,产生一个新地址,,就不会产生上面两种的问题。
function cloneObj(myObj) {
if(typeof(myObj) != 'object') {
return myObj;
}
var newObj;
if(myObj.constructor) {
newObj = new myObj.constructor();
}else {
newObj = {};
}
for(let i in myObj) {
newObj[i] = cloneObj(myObj[i]);
}
return newObj;
}