持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情
一、前言
在开发中偶尔会碰到一些场景是要自己去处理一些数据,为了方便数据的对比,你需要复制一份一样的,这时候就需要用到拷贝了。所谓深浅拷贝,浅拷贝的意思就是,你只是复制了对象数据的引用,并没有把内存里的值另外复制一份,那么深拷贝就是把值完整地复制一份新的值,下面就对深浅拷贝做一个详细了解。
二、浅拷贝
实现浅拷贝的方式
1. Object.assgin()
let obj = {name:'lucky',age:18,a:{sex:nan}}
let change = Object.assign({},obj)
change.name = 'll' //改变当前层
change.a.sex = 'nv' //改变内层
console.log('change----',change)
console.log('obj----',obj)
如下图打印所示,改变当前层级的为浅拷贝,改变嵌套层的为深拷贝
2. Array.prototype.concat()
let arr = [1,2,{name:'lucky'},3]
let change = arr.concat()
change[2].name = 'll'
console.log('arr----',arr)
console.log('change----',change)
验证结果
3. Array.prototype.slice()
let arr = [1,2,{name:'lucky'},3]
let change = arr.slice()
change[2].name = 'll'
console.log('arr----',arr)
console.log('change----',change)
验证结果
4.简单手写一个浅拷贝
function fn(target){
let type = Object.prototype.toString.call(target).slice(8, -1).toLowerCase()
if(type === 'array'){
var copy = []
}else{
var copy = {}
}
for(let key in target ){
// 如果是容器自身的才需要处理
if (target.hasOwnProperty(key)) {
copy[key] = target[key]
}
}
console.log(target)
console.log(copy)
console.log(copy === target)
}
let obj = {name:'lucky',age:18,eat:function(){},a:{name:'li'}}
let arr = [1,2,3,4,5,6]
fn(obj)
fn(arr)
验证结果
三、深拷贝
在很多时候浅拷贝满足不了需求,因为深拷贝才是完整数据的拷贝,深拷贝改变数据不会影响到原数据。
深拷贝的实现方式
1. JSON.parse() 和 JSON.stringify()
let obj = {name:'lucky',age:18}
let change = JSON.parse(JSON.stringify(obj))
change.name = 'll'
console.log('obj----',obj)
console.log('change----',change)
验证结果
原对象数据没有改变
2. 递归写法
//检测类型函数
function checkType(obj) {
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}
//深拷贝
function deepClone(obj){
//判断类型 如果是基本类型 则直接返回 如果是对象类型,则开始拷贝
if (checkType(obj) === 'object') {
var newObj = {};
} else if (checkType(obj) === 'array') {
var newObj = [];
} else {
return obj;
}
//拷贝
for (var key in obj) {
//每次拷贝之前 把拷贝的递归一下,如果是基本值,则直接返回,否则再次拷贝
newObj[key] = deepClone(obj[key]);
}
return newObj;
}
let obj = {name:'lucly',
eat:function(){},
a:{sex:'nan'}
}
let result = deepClone(obj)
result.name = 'll'
console.log('obj----',obj)
console.log('result----',result)
验证结果
递归深拷贝完成
3.最终写法
因为递归写法消耗性能比较大,如果对象里面循环引用,那么就会存在爆栈现象,所以我们再优化一下写法。
/**
解决问题: 循环引用正常
注意: 在整个递归调用过程中, 只有一个map在反复使用
**/
function deepClone (target, map=new Map()) {
if (target!==null && typeof target==='object') { // 非函数的对象
// const map = new Map() // 用来缓存target与其对应的拷贝对象的容器
// 从缓存中取出对应的拷贝对象,如果有了, 直接返回它
let clone = map.get(target)
if (clone) return clone
// 如果没有, 创建一个新拷贝空容器, 缓存起来
clone = Array.isArray(target) ? [] : {}
map.set(target, clone)
// 遍历target中所有数据, 依次添加到新容器
for (const key in target) { // key是对象的属性名或数组的下标
if (target.hasOwnProperty(key)) { // 如果是容器自身的才需要处理
clone[key] = deepClone(target[key], map) // 对属性值进行克隆处理后保存
}
}
return clone
} else {
return target
}
}
let obj = {name:'lucly',
eat:function(){},
a:{sex:'nan'}
}
let result = deepClone(obj)
result.name = 'll'
console.log('obj----',obj)
console.log('result----',result)
好了,以上就是本篇文章的分享,感谢阅读!