一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
前言
js中的深拷贝、浅拷贝是一个非常常见的问题,不管是面试还是日常的工作中都会遇到,之前有一篇文章介绍过什么是深拷贝和浅拷贝,有兴趣的可以点击查看,这里就不再做过多的赘述,本文主要介绍一些实现拷贝的方法和如何自己写一个深拷贝和浅拷贝。
数组中可使用slice()和concat()实现拷贝
例子:
var oldArr= [1,2,3,4,5]
var newArr = oldArr.concat()
//slice同理,var newArr = oldArr.slice()
newArr[0]=6
console.log(oldArr,newArr)
结果如下:
看起来好像实现了深拷贝,但如果数组中的项也是数组就会出问题,如下:
var oldArr= [1,[2,3],4,5]
var newArr = oldArr.slice()
newArr[1][0]=6
console.log(oldArr,newArr)
结果如下:
旧数组也跟着改变了,由此可知slice()和concat()只能实现浅拷贝(如果数组的元素不是基本类型,拷贝的是数组的引用)
JSON.parse(JSON.stringify(arr))
通过JSON.parse(JSON.stringify(arr))可以实现数组和对象的深拷贝,如下
var oldArr= [1,[2,3],4,5]
var newArr = JSON.parse( JSON.stringify(oldArr) )
newArr[1][0]=6
console.log(oldArr,newArr)
结果如下:
实现一个浅拷贝
我们已经知道的浅拷贝就是只拷贝单层数据,那也就是只要一层for循环就行了,在每次循环中只要把属性名和属性值给新对象就可以了,代码如下
function shallowCopy(obj){
//这里判断一下,只拷贝数组和对象
if(typeof obj !== 'object'){
return
}
var newObj = obj instanceof Array ? []:{} //这里必须判断是不是数组而不能判断是不是对象,因为数组也是对象
for (let key in obj){
if(obj.hasOwnProperty(key)){ //这里加hasOwnProperty()是判断当前项是不是本身的,因为用for...in遍历数组的时候会遍历到原型链上的属性
newObj[key] = obj[key]
}
}
return newObj
}
var oldArr= [1,[2,3],4,5]
var newArr =shallowCopy(oldArr)
newArr[1][0]=6
console.log(oldArr,newArr)
验证结果如下:
实现一个深拷贝
上面提到了浅拷贝是只拷贝一次,深拷贝是完全的拷贝,那我们可以在上面浅拷贝的基础上来实现深拷贝,只需要当当前项是数组和对象的时候递归调用即可,代码如下
function deepCopy(obj){
if(typeof obj !== 'object'){
return
}
var newObj = obj instanceof Array ? []:{}
for (let key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] !=='object'){
newObj[key] = obj[key]
}else{
newObj[key]=deepCopy(obj[key])
}
}
}
return newObj
}
var oldArr= [1,[2,3],4,5]
var newArr =deepCopy(oldArr)
newArr[1][0]=6
console.log(oldArr,newArr)
验证结果如下:
总结
在日常开发中深拷贝还是很重要,特别是当对数组和对象进行操作时,一定要记得考虑是否需要深拷贝,要不就可能出现奇怪的问题。