在js中,数据类型类型可分为值类型(基本类型)和引用类型。值类型有:字符串(String)、布尔(Boolean)、数字(Number)、对空(Null)、未定义(undefined)、Symbol。引用类型:对象(Object)、数组(Array)、函数(Function)。这两种类型的不同,使得在拷贝的时候也会有差异。值类型拷贝的时候直接赋值就好,但是在引用类型的对象和数组中,如果直接整体赋值的话有的时候是会有问题的。在项目中,我们经常需要保存一份原始数据,然后拷贝一份原始数据进行更改,那么如果这个数据是Object或者Array类型,我们直接拷贝的话,他们还是指向的同一个地址,所以,当我们改变其中的一个值或者新增一个属性时,另一份也会跟着变化,这肯定不是我们想要的结果,那么今天就总结一下js中,对象、数组拷贝的问题。
拷贝的问题也是分为两种,一种是浅拷贝、另一种是深拷贝。在总结之前,我们先定义一个较复杂的对象名为Obj,后面的代码都是使用该对象进行更改的,具体结构如下:
let Obj = {
name:'zhang',
age:18,
score:{
Chinese:98,
English:88,
Math:98
},
like:[{
sports:5
},
{
sports:4
},{
sports:3
}]
}
一、浅拷贝
1、浅拷贝之使用Object.assign方式
function ObjCopy1(){
let Obj1 = Object.assign({},Obj,);
Obj1.name = 'zhang1';
Obj1.like[1].sports = 55;
Obj1.score.Chinese = 100,
console.log('Obj.name:',Obj.name,' Obj.like[1].sports:',Obj.like[1].sports,' Obj.score.Chinese:',Obj.score.Chinese);
console.log('Obj1.name:',Obj1.name,' Obj1.like[1].sports',Obj1.like[1].sports,' Obj1.score.Chinese:',Obj1.score.Chinese);
}
ObjCopy1();
2、浅拷贝之...运算符实现
function ObjCopy2(){
let Obj2 = {...Obj};
Obj2.name = 'zhang1';
Obj2.like[1].sports = 55;
Obj2.score.Chinese = 100,
console.log('Obj.name:',Obj.name,' Obj.like[1].sports:',Obj.like[1].sports,' Obj.score.Chinese:',Obj.score.Chinese);
console.log('Obj2.name:',Obj2.name,' Obj2.like[1].sports',Obj2.like[1].sports,' Obj2.score.Chinese:',Obj2.score.Chinese);
}
ObjCopy2();
3、浅拷贝之一重循环直接遍历
function ObjCopy3(Obj){
let Obj3={};
for (let item in Obj){
Obj3[item] = Obj[item]
}
Obj3.name = 'zhang1';
Obj3.like[1].sports = 55;
Obj3.score.Chinese = 100,
console.log('Obj.name:',Obj.name,' Obj.like[1].sports:',Obj.like[1].sports,' Obj.score.Chinese:',Obj.score.Chinese);
console.log('Obj3.name:',Obj3.name,' Obj3.like[1].sports',Obj3.like[1].sports,' Obj3.score.Chinese:',Obj3.score.Chinese);
}
通过结果可以看到,通过以上三种方式实现的拷贝都是浅拷贝,当嵌套多层Object或Array时,我们更改value中的对象或Array的值时,原始数据也跟着变化了。
二、深拷贝
1、深度拷贝之使用JSON.parse()和JSON.stringify()
function ObjCopy4(){
let Obj4 = JSON.parse(JSON.stringify(Obj));
Obj4.name = 'zhang1';
Obj4.like[1].sports = 55;
Obj4.score.Chinese = 100,
console.log('Obj.name:',Obj.name,' Obj.like[1].sports:',Obj.like[1].sports,' Obj.score.Chinese:',Obj.score.Chinese);
console.log('Obj4.name:',Obj4.name,' Obj4.like[1].sports',Obj4.like[1].sports,' Obj4.score.Chinese:',Obj4.score.Chinese);
}
ObjCopy4();
2、利用递归,自定义深度拷贝
function ObjCopy5(){
function copy (Obj) {
var newObj = Obj.constructor === Array ? [] : {};
if(typeof Obj !== 'object'){
return;
}
for(var i in Obj){
newObj[i] = typeof Obj[i] === 'object' ?
copy(Obj[i]) : Obj[i];
}
return newObj
}
var Obj5 = copy(Obj)
Obj5.name = 'zhang1';
Obj5.like[1].sports = 55;
Obj5.score.Chinese = 100,
console.log('Obj.name:',Obj.name,' Obj.like[1].sports:',Obj.like[1].sports,' Obj.score.Chinese:',Obj.score.Chinese);
console.log('Obj5.name:',Obj5.name,' Obj5.like[1].sports',Obj5.like[1].sports,' Obj5.score.Chinese:',Obj5.score.Chinese);
}
这两种方法都能实现深度拷贝,此处只是针对Object和Array,Function的不一定能够拷贝成功。一般情况下针对只含有Object和Array的对象拷贝时,使用JSON.parse()和JSON.stringify()方法拷贝是非常简单的。此处我只总结了5种方法,如果有其它的方法,也希望大家能够多分享哦。