javascript中一般有按值传递和按引用传递两种复制方式:
- 按值传递的是基本数据类型(Number,String,Boolean,Null,Undefined,Symbol)
- 按引用传递的是引用类型(Object,Array,Function)
拷贝分为浅拷贝与深拷贝两种方式:
- 浅拷贝只是增加了一个指针指向已经存在的内存,两个js 对象指向同一个内存地址,其中一个改变会影响另一个;
- 深拷贝则是增加了一个指针并且申请一个新的内存,新对象重新指向一个新的内存地址,两个对象改变互不影响。
1、对象拷贝:拿到对象A的属性一个个插入到新的对象B中
let student = {
id:1001,
name:'张三',
age:19
};
//拿到的属性一个个插入到新对象的属性中
let student1 = {};
student1.id = student.id;
student1.name = student.name;
student1.age = student.age;
student1.id = 1002;
console.log(student.id); //输出1001
console.log(student1.id); //输出1002
由于经常要用到拷贝,把拷贝的代码封装成一个函数
let student = {
id:1001,
name:'张三',
age:19
};
//对象拷贝
function objClone(obj){
let objResult = {};
for(let key in obj){
objResult[key] = obj[key];
}
return objResult;
}
let student1 = objClone(student);
student1.id = 1002;
console.log(student.id); //输出1001
console.log(student1.id); //输出1002
2、浅拷贝:只拷贝最外层的数据,对于更深层次只拷贝引用(即拷贝了数据地址,若改变数据则会相互影响)
let student ={
id:1001,
name:'张三',
age:19,
address:{
country:'中国',
city:'厦门'
}
};
function simpleClone(obj){
let objResult = {};
for(let key in obj){
objResult[key] = obj[key];
}
return objResult;
}
//浅拷贝
let student1 =simpleClone(student);
student1.id = 1002;
student1.address.city = '泉州';
console.log(student.id); //输出1001
console.log(student1.id); //输出1002
//student1.address = student.address; //对象的赋值,是引用,修改新对象的属性,原对象也会发生改变
console.log(student.address.city); //输出 泉州
console.log(student1.address.city); //输出 泉州
解决方式:判断student[key]是否是对象,如果是再处理一次拷贝。
let student ={
id:1001,
name:'张三',
age:19,
address:{
country:'中国',
city:'厦门'
}
};
let student1 = {};
for(let key in student){
//判断student[key]是否是对象,如果是还要在处理一次拷贝。
let obj = student[key];
if(typeof obj ==='object'){
student1[key] = {};
for(let key1 in obj){
//处理student[key]属性的拷贝
student1[key][key1] = obj[key1];
}
}
else{
//一个一个赋值
student1[key] = obj;
}
}
student1.address.city = '泉州';
console.log(student.address.city); //输出 厦门
console.log(student1.address.city); //输出 泉州
3、深拷贝(对象):一层一层地拷贝,利用递归来实现每一层都重新创建对象并赋值。
深拷贝拷贝了数据(不再是拷贝地址),改变数据不再相互影响。
let student ={
id:1001,
name:'张三',
age:19,
address:{
country:'中国',
city:'厦门',
menpai:{
qu:'集美区',
loudong:'软件园三期A03栋'
}
}
};
//深拷贝
function deepClone(obj){
let objResult = {};
for(let key in obj){
//如果是对象
if(typeof obj[key] === 'object'){
//递归调用deepClone,一个个拷贝
objResult[key] = deepClone(obj[key]);
}
else{
//赋值
objResult[key] = obj[key];
}
}
return objResult;
}
let student1 = deepClone(student);
student1.id = 1002;
student1.address.city = '泉州';
student1.address.menpai.qu='思明区';
console.log(student.id); //输出1001
console.log(student1.id); //输出1002
console.log(student.address.city); //输出 厦门
console.log(student1.address.city); //输出 泉州
console.log(student.address.menpai.qu); //输出 集美区
console.log(student1.address.menpai.qu); //输出 思明区
4、深拷贝(数组):数组是特殊对象,key是数字,即数组的赋值也是引用,所以要对传入的obj进行区分。
console.log(typeof[]); //输出 object
console.log(typeof{}); //输出 object
function deepClone(obj){
//判断是对象还是数组
let objResult = Array.isArray(obj)?[]:{};
for(let key in obj){
//如果是对象 []和{}的类型都是object
if(typeof obj[key] === 'object'){
//递归调用deepClone,一个个拷贝
objResult[key] = deepClone(obj[key]);
}
else{
//赋值
objResult[key] = obj[key];
}
}
return objResult;
}
let arr =[1,2,3,4];
let arr1 =deepClone(arr);
arr1[0] = 5;
console.log(arr); //输出 1 2 3 4
console.log(arr1); //输出 5 2 3 4
let arr =[1,2,3,{a:1,b:2},[1,2,3,4],4];
let arr1 =deepClone(arr);
arr1[0] = 5;
arr1[3].a = 100;
arr1[4][0] =1000;
console.log(arr); //输出 1 2 3 {a:1,b:2} [1,2,3,4] 4
console.log(arr1); //输出 5 2 3 {a:100,b:2} [1000,2,3,4] 4