1.首先我们先来理解一下什么是浅拷贝,什么是深拷贝吧
浅拷贝(对象/数组) 特点:
- 拷贝的是引用(即地址值),修改拷贝以后的数据,会影响原数据
- 拷贝数据的方法(浅拷贝)
1. 直接赋值给一个变量 //浅拷贝
2. Object.assign() //浅拷贝
3. Array.prototype.concat() //浅拷贝
4. Array.prototype.slice() //浅拷贝
- 下面我们用代码来辅助理解
// 1. 直接赋值给一个变量 //浅拷贝
let obj1 = {name:'coderlyk',age:31}
let obj2 = obj1
obj2.name = "newname"//obj1和obj2的name属性值都改变了,浅拷贝
console.log(obj1,obj2)//两个对象都返回{name:'newname',age:31}
// 2. Object.assign() //浅拷贝
let obj1 = {name:'kobe',age:29}
let obj2 = Object.assign(obj11)
obj2.name = "wade"//obj1和obj2的name属性值都改变了,浅拷贝
console.log(obj1,obj2)//两个对象都返回 {name:'wade',age:29}
// 3. Array.prototype.concat() //浅拷贝
let arr1 = [1,2,true,{name:'TT',age:26}]
let testArr = [3,4]
let arr2 = arr1.concat(testArr)
console.log(arr2)
arr2[1] = "a"//只改变了arr2
arr2[3].name="james"//arr1[3]和arr2[3]的name属性值都改变了,浅拷贝
console.log(arr1,arr2)
// 4. Array.prototype.slice() //浅拷贝
let arr1 = [3,8,false,{name:'冷嘉琪',age:18}]
let arr2 = arr2.slice()
arr2[3].name = '大帅哥'//arr1[3]和arr2[3]的name属性值都改变了,浅拷贝
console.log(arr1,arr2)
深拷贝(深度克隆)特点:
- 拷贝后,生成一块新的内存来存放拷贝的数据,修改拷贝以后的数据,不会影响原数据
- 拷贝数据的方法(深拷贝)
1.JSON.parse(JSON.stringify(arr/obj)) //深拷贝(深度克隆),
注意:拷贝的数据里不能有函数,不能处理
- 下面我们用代码来辅助理解
// 5. JSON.parse(JSON.stringify(arr/obj)),深拷贝(深度克隆),拷贝的数据里不能有函数,处理不了
let arr1 = [3,8,false,{name:'oldname',age:20},function fun(){console.log('fun')}]
let arr2 = JSON.parse(JSON.stringify(arr1))
//先通过JSON.stringify方法将arr1变成JSON字符串,再通过方法JSON.parse将JSON字符串转成数组,从而实现拷贝
arr2[3].name = 'newname'//arr2[3]的name属性值改变了,arr1[3]的name属性值没变,深拷贝
console.log(arr1)//(5) [3, 8, false, {…}, ƒ]
console.log(arr2)//(5) [3, 8, false, {…}, null] //函数拷贝过来变成了null
2.如何实现深度克隆
2.1 了解如何判断数据类型,并将判断之后的数据类型的相应字符串提取出来,方便我们实现深度克隆时进行判断
let n = null
console.log(typeof n)//object
let result = Symbol('lyk')
console.log(Object.prototype.toString.call(result))// [object Symbol]
console.log(typeof Object.prototype.toString.call(result))//string -》说明返回的[object Symbol] 是一个字符串
//提取判断后数据类型字符串
console.log(Object.prototype.toString.call(result).slice(8,-1))//Symbol
2.2 将我们深度克隆的全部代码逻辑奉上
// 1. 定义检查数据类型的功能函数
function checkedType(target){
return Object.prototype.toString.call(target).slice(8,-1)//如 [Object Array] 我们这样截取的就是Array
}
// 2.实现深度克隆 ---> 对象/数组
function clone(target){
// 判断拷贝的数据类型
// 初始化变量result 成为最终克隆的数据
let result, targetType = checkedType(target)
if(targetType === 'Object'){
result = {}
}else if (targetType === 'Array') {
result = []
}else{
return target
}
// 遍历目标数据
for(let i in target){
// 获取遍历数据的每一项值
let value = target[i]
// 判断目标结构里的每一个值是否存在对象/数组
if(checkedType(value) === 'Object' || checkedType(value) === 'Array'){// 对象/ 数组里嵌套了对象/数组
//继续遍历获取到的value值
result[i] = clone(value)//递归
}else {//获取到的value值是基本的数据类型或者是函数
result[i] = value
}
}
return result;
}
let fun = function(){
console.log('我是fun函数')
}
let setArr = [1,5,true,{name:'boss',age:40},fun]
let setNew = clone(setArr)
setNew[3].name = "大boss"
console.log(setArr,setNew)
setNew[4]()