一文带你了解JavaScript深拷贝

深拷贝之前的文章我也写过,今天就来重新了解一下JavaScript的深拷贝吧。博客链接

拷贝是啥?

顾名思义也就是复制,我们知道在JavaScript中基本数据类型都是保存在栈中的,而复杂数据类型(object)是保存在堆中的,在栈中不过是保存了堆的地址(引用)。

浅拷贝与深拷贝

浅深拷贝都是对引用类型的数据而言的,基本数据类型一赋值就开辟了独立的栈空间,互不影响。

  • 浅拷贝:当我们对基本数据类型复制,会把值全部复制过去的。如果是引用类型,也是把值复制过去,不过这个值是地址引用。这样如果其中一个对象改变了这个地址,就会影响到另一个对象。
  • 深拷贝:是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
//基本数据类型
let a = 1
let b = a
b = 2  //b的值为2,a的值为1互不影响
//基本数据类型
let a = [1,2,3]
let b = a
b[0] = 2  //b的值为[2,2,3],a的值为[2,2,3]引用了同一个对象

赋值&&浅拷贝&&深拷贝的区别

赋值:只是在栈中新建一个变量,指向同一个堆内存,也就是把地址复制过来。
浅拷贝:会新建个一对象,如果属性是基本类型,则拷贝基本数据类型的值,如果是引用数据类型,则拷贝内存地址。因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
来看看下面的例子

//赋值
let a = {
	name:'lisi',
	hobby:[1,2,[3,4],5,6]
}
let b = a
b.name = 'zhangsan'
b.hobby = [3,4,10]
//a和b的值都为{name:'zhansan',hobby:[3,4,10]}
//浅拷贝
let a = {
	name:'lisi',
	hobby:[1,2,[3,4],5,6]
}
let b = shallowClone(a)
b.name = 'zhangsan'
b.hobby[1] = 10 // 新旧对象还是共享同一块内存
//a的值为{name:'lisi',hobby:[1,10,[3,4],5,6]}
//b的值为{name:'zhangsan',hobby:[1,10,[3,4],5,6]}
function shallowClone(source) {
	var target = {};
	for(var i in source) {
		if (source.hasOwnProperty(i)) {
			target[i] = source[i];
		}
	}
	return target;
}
//深拷贝
let a = {
	name:'lisi',
	hobby:[1,2,[3,4],5,6]
}
let b = JSON.parse(JSON.stringify(a)) //比较简单地实现深拷贝
b.name = 'zhangsan'
b.hobby[1] = 10 // 新旧对象不是同一块内存
//a的值为{name:'lisi',hobby:[1,2,[3,4],5,6]}
//b的值为{name:'zhangsan',hobby:[1,10,[3,4],5,6]}

浅拷贝实现

Object.assign()

Object.assign()方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

let obj1 = {person:{name:'lisi',age:18},money:666}
let obj2 = Object.assign({},obj1)
obj2.person.age = 20
obj2.money = 777
console.log(obj1) //{person:{name:'lisi',age:20},money:666}
console.log(obj2) //{person:{name:'lisi',age:20},money:777}

注意:当object只有一层的时候,是深拷贝

Array.prototype.concat()
let arr1 = [1,2,{name:'lisi',age:18},3,4]
let arr2 = arr1.concat()
arr2[1] = 10
arr2[2].name = 'zhangsan'
console.log(arr1)//[1,2,{name:'zhangsan',age:18},3,4]
console.log(arr2)//[1,10,{name:'zhangsan',age:18},3,4]
Array.prototype.slice()
let arr1 = [1,2,{name:'lisi',age:18},3,4]
let arr2 = arr1.slice()
arr2[1] = 10
arr2[2].name = 'zhangsan'
console.log(arr1)//[1,2,{name:'zhangsan',age:18},3,4]
console.log(arr2)//[1,10,{name:'zhangsan',age:18},3,4]
展开运算符…
let obj1 = {person:{name:'lisi',age:18},money:666}
let obj2 = {...obj1}
obj2.person.age = 20
obj2.money = 777
console.log(obj1) //{person:{name:'lisi',age:20},money:666}
console.log(obj2) //{person:{name:'lisi',age:20},money:777}
函数库lodash的_.clone方法
let obj1 = {person:{name:'lisi',age:18},money:666}
let obj2 = _.clone(obj1)
obj2.person.age = 20
obj2.money = 777
console.log(obj1) //{person:{name:'lisi',age:20},money:666}
console.log(obj2) //{person:{name:'lisi',age:20},money:777}

深拷贝实现

JSON.parse
//浅拷贝
let a = {
	name:'lisi',
	hobby:[1,2,[3,4],5,6]
}
let b = JSON.parse(JSON.stringify(a)) //比较简单地实现深拷贝
b.name = 'zhangsan'
b.hobby[1] = 10 // 新旧对象不是同一块内存
//a的值为{name:'lisi',hobby:[1,2,[3,4],5,6]}
//b的值为{name:'zhangsan',hobby:[1,10,[3,4],5,6]}

这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringifyJSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。

jQuery.extend()方法

jquery 有提供一個 . e x t e n d 可 以 用 来 做 D e e p C o p y ; ‘ .extend可以用来做 Deep Copy;` .extendDeepCopy;.extend(deepCopy, target, object1, [objectN])//第一个参数为true,就是深拷贝`

let obj1 = {person:{name:'lisi',age:18},money:666}
let obj2 = $.extend(true,{},obj1)
console.log(obj1.person === obj2.person) //false
函数库lodash的_.cloneDeep方法
let obj1 = {person:{name:'lisi',age:18},money:666}
let obj2 = _.cloneDeep(obj1)
console.log(obj1.person === obj2.person) //false
手写深拷贝
function deepClone(obj){
	if(obj === null) return obj //如果是null返回空
	if(typeof obj !== 'object') return obj //如果是基本数据类型或者函数,直接返回
	//返回新的日期或者正则对象
	if (obj instanceof Date) return new Date(obj);
	if (obj instanceof RegExp) return new RegExp(obj);
	//新建一个对象,如果是数组就是new Array() 否则是 new Object()
	let cloneObj = new obj.constructor();
	for(let key in obj){
		if(obj.hasOwnProperty(key)){
			cloneObj[key] = deepClone(obj[key]); //递归调用
		}
	}
	return cloneObj;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LVS(Linux Virtual Server)是一种基于 Linux 系统的负载均衡集群技术,它主要用于将网络流量分发到多个服务器上,以提高系统的可靠性、可扩展性和性能。 LVS 集群一般包括四个组件:调度器(LVS 调度器)、前端服务器(负载均衡器)、后端服务器(真实服务器)和存储服务器(用于共享数据)。首先,调度器接收来自客户端的请求,然后根据配置的调度算法(如轮询、加权轮询、最小连接数等)将请求分发到多个前端服务器。前端服务器接收到请求后,通过相应的负载均衡算法将请求转发到后端的真实服务器上进行处理。在整个过程,存储服务器用于存放共享的数据,以确保所有的真实服务器都能获取到相同的数据,并提供一致的服务。 LVS 集群的优点是能够提高网站的稳定性和可靠性,当某一台服务器出现故障时,调度器会自动将请求分发到其他可用的服务器上,从而保证服务的连续性。同时,LVS 集群还能够通过增加前端服务器和后端服务器的数量来提高系统的性能和吞吐量,以满足不断增长的用户需求。 在实际应用,LVS 集群需要合理配置,包括选择合适的调度算法、调整每台服务器的权重、选择适当的硬件设备等。此外,还需要及时监控集群的运行状态,及时发现和解决故障,以确保整个系统的正常运行。 总的来说,LVS 负载均衡集群是一种强大而高效的集群技术,能够帮助企业提高系统的可靠性和性能,是现代互联网应用不可或缺的重要组成部分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值