浅拷贝
在内存中新开辟一个内存空间 创建一个新对象
拷贝原对象的第一层 基本数据类型的值 和引用类型的地址
在堆内存中新开辟空间 创建一个新的对象 拷贝第一层的普通数据类型的值和引用类型的地址
实现浅拷贝的方式
深拷贝
在堆内存中新开辟一个空间存放新的对象
递归的拷贝原对象的所有属性和方法 拷贝前后两个对象 相互不影响
实现深拷贝的方式
- JSON.parse(JSON.stringify(obj))
- 手写递归实现
- 使用一些JS库,比如lodash等
利用 JSON实现深拷贝会有一些缺陷
const obj = {
name: 'zjl',
age: 18,
hobby: ['dance', 'music'],
book: {
book_name: 'Golang',
price: 66
},
test1: function () {},
test2: undefined,
test3: Symbol('id'),
test4: new RegExp(/a/, 'g'),
test5: NaN,
test6: Infinity,
test7: new Date()
}
// JSON.parse() 将JSON格式的字符串转为对象
// JSON.stringify() 将对象转为JSON格式的字符串
const res = JSON.parse(JSON.stringify(obj))
console.log(res)
打印结果如图:
缺陷:
- 拷贝对象的属性值如果是 function / undefined / Symbol , 这个键值对丢失!
- 如果拷贝对象的属性值是RegExp, 会变成{}
- 如果NaN, Infinity 会变成null
- 拷贝Date日期对象,会变成日期字符串
什么是递归
自己调用自己
递归也可以看作是一种循环(不断的自己调用自己) 循环有终止条件 递归当然也需要有终止条件
function fn(n) {
if (n === 1) {
return 1
}
return n + fn(n - 1)
}
fn(3);
// fn(3) ==> 3 + fn(2) ==> 3 + 2 + fn(1) ===> 3 + 2 + 1 ==> 6
// const res = fn(3)
// console.log(res)
// fn(5) ==> 5 + fn(4) ==> 5 + 4 + fn(3) ==> 5 + 4 + 3 + fn(2)
// ==> 5 + 4 + 3 + 2 + 1 ===> 15
递归注意问题 :
递归爆栈 (栈溢出)
栈是一种数据解构 ,栈有深度 如果超出了就会造成栈溢出
报错 : Maximum call stack size exceeded
手写递归
const obj = {
name:'小鸣',
age: 12,
hobby:['aaa','bbb'],
like:{
rap:'只因你太美',
jump:'铁山靠'
}
}
const o = {};
const deepClone = (newObj,oldObj)=>{
for(let k in oldObj){
// 这里数组的判断一定要写在对象前 因为数组的本质也是对象
if(oldObj[k] instanceof Array){ //如果值是数组
newObj[k] = []
deepClone(newObj[k],oldObj[k]);
}else if(oldObj[k] instanceof Object){//如果值是对象
newObj[k] = {}
deepClone(newObj[k],oldObj[k])
}else{
newObj[k] = oldObj[k]
}
}
}
deepClone(o,obj);
console.log(o);