js的深拷贝与浅拷贝

26 篇文章 1 订阅

前言:在说拷贝之前,先说说js中的数据存储,我们知道js这广义上数据类型分为两种,原始数据类型和引用数据类型,原始数据类型包括string,boolean,number,null,undefined,symbol,引用类型有Function,Array,Object,Date,RegExp等等其实这些都可以归总为Object类型。

对于原始类型数据,赋值即是拷贝,因为原始类型栈里存的就是其值。对于复杂类型来说,变量存储的是对象在堆空间里的地址值,如果进行赋值,赋值仅仅是将其地址值给另一个变量,实际上这两个变量都指向同一地址。

//原始类型赋值,a,b的值相互不影响
let a = 23
let b = a
//复杂类型,当d的name改变,c的name改变,因为它们指向的就是同一对象
let c = {
    name:"sd"
}
let d = c

现在,我们知道了拷贝就是为了生成两份互相不影响的数据,同时我们知道原始类型的赋值即拷贝,而对象的属性可能由原始数据类型组成,也有可能由对象类型组成,所以我们分类考虑。

var obj = {
    name:"张三",
    time: 12312313
}

//1、赋值操作
var obj2 = obj

//2、拷贝
var obj3 = {}

for(let key in obj) {
   obj3[key] = obj[key]
}

如上,第二个我们简单实现了拷贝。不过稍微思考一下,我们会发现,如果obj的属性也是一个复杂类型呢?

var obj = {
    o : {
        name:"asd"
    },
    age:23
}
var obj2 = {}
for(let key in obj) {
    obj2[key] = obj[key]
}

obj2.o.name = "张三"

obj.o.name //张三

如上代码,按照开始的方法我们进行拷贝,拷贝后,我们发现obj.o与obj2.o指向的还是同一对象。如果我们需要完全拷贝,就得对obj.o也进行遍历。

得出结论

1、浅拷贝:浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。(ES6的Object.assign方法就是进行浅拷贝)

2、深拷贝:深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

3、实现深拷贝

function deepCopy(o) {
	if(o instanceof Date) return new Date(o) //日期类直接返回
	if(o instanceof RegExp) return new RegExp(o) //正则直接返回
	if(o === null || typeof o !== "object") return o //原始类型直接返回
	let c = new o.constructor()
	for(let key in o) {
		if(o.hasOwnProperty(key)) {
			c[key] = deepCopy(o[key])
		}
	}
	return c
}

优化,上面的深拷贝还有一点问题,如果出现循环引用,将会陷入死递归,导致程序崩溃。

function deepCopy(o,map = new WeakMap()) {
    if(o instanceof Date) return new Date(o) //日期类直接返回
    if(o instanceof RegExp) return new RegExp(o) //正则直接返回
    if(o === null || typeof o !== "object") return o //原始类型直接返回
    if(map.has(o)) {
        return map.get(o)
    }
    let c = new o.constructor()
    map.set(o,c)
	for(let key in o) {
		if(o.hasOwnProperty(key)) {
			c[key] = deepCopy(o[key])
		}
	}
	return c
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值