JavaScript-浅拷贝与深拷贝的方式

1. 直接赋值,值拷贝和引用拷贝

** js中的基本数据类型:String Number Boolean Null Undefined,在赋值的过程中都是值拷贝 **

var a1 = 1;
var b1 = a1;
console.log(a1 == b1); //true
console.log(a1 === b1); //true

** js中的对象数据类型:Object Array Function Map Set,在赋值过程中都是引用拷贝 **

var a2 = {name: '张三', age: 18, fans: function() {return 0}};
var b2 = a2;
a2.age = 28;

console.log(a2 == b2); //true
console.log(a2 === b2); //true
console.log(b2.age);

2.1 Object.assign() [ES6]

var c2 = Object.assign(a2);
// 测试 Object.assign(a2, {}),即源对象为空对象,仍然为浅拷贝
a2.age = 30;
console.log(c2 === a2); //true
console.log(c2.age); //30

关于Object.assign()

Object.assign() 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象。
	const target = { a: 1 };
	const source1 = { b: 2 };
	const source2 = { c: 3 };
	Object.assign(target, source1, source2);
	console.log(target); // {a:1, b:2, c:3}
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
	const target = { a: 1, b: 1 };
	const source1 = { b: 2, c: 2 };
	const source2 = { c: 3 };
	Object.assign(target, source1, source2);
如果只有一个参数,Object.assign()会直接返回该参数。(**即实现浅拷贝)
	const obj = {a: 1};
	Object.assign(obj) === obj // true
如果该参数不是对象,则会先转成对象,然后返回。(由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。)
	typeof Object.assign(2) // "object"

3. 深拷贝

3.1 array.slice(0)

var a3 = [1, 2, 3];
var b3 = a3.slice(0);
console.log(a3 == b3); // false
array.slice(0)返回一个新数组

slice(start, end)截取数组内元素
数组名.slice(start, end) 表示从数组中截取 start(包括)位置索引到end(不包括)
即左闭右开[...)
如果不写end,就会截取到数组的最后
该方法不会改变原数组结构,只是将新提取的元素作为一个新数组返回

3.2 array.concat()

var a4 = [1, 2, 3, 4]; 
var b4 = a4.concat();
console.log(a4 == b4); //false
concat() 合并数组并返回新的数组
	var arr1 = [1, 2];
	var arr2 = [3, 4];
	var arr3 = [5, 6, 7];
	var arr = arr1.concat(arr2, arr3);
	console.log(arr) // [1, 2, 3, 4, 5, 6, 7];

3.3 JSON.parse(JSON.stringify(oldobj))

var a5 = {fans: function() {}, gender: undefined, name: '123', date: new Date()};
var b5 = JSON.parse(JSON.stringify(a5));
console.log(b5); // {name: '123', date: '2022-07-14T14:23:13.720Z'}
console.log(b5 == a5); //false
对象中的属性值如果为函数func或者值为underfined,这个属性会消失;
如果值是时间对象,则转换为字符串格式

3.4 for…in 或 for循环

 var b6 = {};
for(var key in a2) {
	console.log(key);
	console.log(a2[key]);
	b6[key] = a2[key];
}
console.log(a2, b6); // {name: '张三', age: 30, fans: ƒ}

3.5 Object.assign({}, oldObj) [ES6]

在1.2中已说明Object.assign()的用法

 var b8 = Object.assign({}, a2);
console.log(b8 == a2); // false

3.6 Object.create(oldObj);???

待研究

var b9 = Object.create({name: '张三'});
console.log(b9);

3.7 扩展运算符 [ES6]

var b10 = { ...a2 };
console.log(b10);
console.log(b10 == a2);

3.8 arr.map(val => {return val})

// arr.map()方法遍历处理数组中每个数据并返回新数组,如不作特殊处理则直接返回与原数组内容相同的新数组
var a13 = [1, 2, 3, 4, 5];
var b13 = a13.map(val => {return val});
console.log(b13);
console.log(a13 == b13); // false

3.9 深拷贝 Array.from(oldArr) [ES6]

// Array.from() 方法对一个类数组或者可迭代对象创建一个新的数组
var a14 = [1, 5, 6, 5, 7];
var b14 = Array.from(a14);
console.log(a14);
console.log(a14 == b14); // false

3.10 完全深拷贝 自定义函数deepClone()

var a11 = {
	name: '张三',
	age: 22,
	girls: [1, 2, 3, {name: '李四'}]
}
var b11 = {... a11};
// 如果对象中某个值是引用数据类型(girls),使用深拷贝模式其实也只拷贝了引用地址,所以还是浅拷贝
b11.girls.push(3);
console.log(a11.girls); // [1, 2, 3, {name: '李四'}, 3] 
// 即a11的girls和b11的girls相互影响
// 解决办法:自行封装函数,完全深拷贝
var a11 = {
	name: '张三',
	age: 22,
	girls: [1, 2, 3, {name: '李四'}]
}
var b12 = deepClone(a11); // 完全深拷贝
a11.girls.push('王五');
console.log(b12.girls); // 不受影响


function deepClone(oldObj) {
//先确定新创建一个数组还是对象,判断对象的数据类型,Array还是Object
	var newObj = Array.isArray(oldObj) ? [] : {};
	// 确定oldObj 不为空,而是一个对象
	if(oldObj && typeof oldObj === 'object') {
		for(var key in oldObj) {
			// 循环获取键名和键值
			// 键名 key
			// 键值 oldObj[key]
			if(oldObj[key] && typeof oldObj[key] === 'object') {
				//判断oldObj 的子元素 oldObj[key]是否为对象,如果是,递归复制
				newObj[key] = deepClone(oldObj[key]);
			} else {
				//不是引用数据类型,就简单复制
				newObj[key] = oldObj[key];
			}
		}
	}
	return newObj;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值