天天看点

【JavaScript语法】函数对象的浅拷贝、深拷贝

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