目录
浅拷贝
常见方法:
- 拷贝对象:Object.assgin() / 展开运算符 {...obj} 拷贝对象
- 拷贝数组:Array.prototype.concat() 或者 [...arr]
1.对象拷贝
assign
// 1. 对象拷贝
// const obj = {
// name: '佩奇'
// }
// 1.1 Object.assign()
// const newObj = {}
// Object.assign(newObj, obj)
// // console.log(newObj)
// console.log(newObj === obj) // false
// newObj.name = '乔治'
// console.log(obj)
// console.log(newObj)
...obj
// 1.2 展开运算符
// const newObj = { ...obj }
// console.log(newObj === obj) // false
// newObj.name = '乔治'
// console.log(obj)
// console.log(newObj)
2. 数组拷贝
2.1 concat 方法实现数组浅拷贝
// // 2. 数组拷贝
// const arr = ['佩奇', '乔治']
// 2.1 concat 方法实现数组浅拷贝
// const arr1 = []
// const newArr = arr1.concat(arr)
// console.log(newArr)
// newArr[1] = '猪爸爸'
// console.log(arr)
// console.log(newArr)
2.2 展开运算符
// 2.2 展开运算符
// const newArr = [...arr]
// console.log(newArr)
// newArr[1] = '猪爸爸'
// console.log(arr)
// console.log(newArr)
注意点:
深拷贝:
深拷贝:拷贝多层,不再拷贝地址
常见方法:
-
-
- 通过 JSON 序列化实现
- lodash库 实现
- 通过递归实现
-
通过JSON序列化实现
JSON.stringify() 序列化为 JSON 字符串,然后再JSON.parse() 转回对象格式
<body>
<script>
// 深拷贝实现方式一:JSON序列化(常用的方式)
// const obj = {
// name: '佩奇',
// family: {
// father: '猪爸爸'
// },
// hobby: ['跳泥坑', '唱歌']
// }
// // console.log(JSON.stringify(obj))
// // console.log(JSON.parse(JSON.stringify(obj)))
// const newObj = JSON.parse(JSON.stringify(obj))
// console.log(newObj === obj) // false
// newObj.family.father = 'dad'
// console.log(obj)
// console.log(newObj)
// 注意事项:JSON.stringify序列化的时候会忽略 function undefined
const obj = {
name: '佩奇',
love: undefined,
family: {
father: '猪爸爸'
},
hobby: ['跳泥坑', '唱歌'],
sayHi() {
console.log('我会唱歌')
}
}
const newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)
</script>
</body>
缺点:function 或 undefined等,在序列化过程中会被忽略
js库 lodash实现深拷贝
官网地址:Lodash 简介 | Lodash中文文档 | Lodash中文网
<body>
<!-- 引入lodash库 -->
<script src="./js/lodash.min.js"></script>
<script>
const obj = {
name: '佩奇',
love: undefined,
family: {
father: '猪爸爸'
},
hobby: ['跳泥坑', '唱歌'],
sayHi() {
console.log('我会唱歌')
}
}
// lodash 库实现
const newObj = _.cloneDeep(obj)
// console.log(newObj)
newObj.family.father = 'dad'
console.log(obj)
console.log(newObj)
</script>
</body>
通过递归实现深拷贝
递归:
所谓递归就是一种函数调用自身的操作
- 简单理解:函数内部自己调用自己, 就是递归,这个函数就是递归函数
- 递归函数的作用和循环效果类似
- 由于递归很容易发生“栈溢出”错误(stackoverflow),所以记得添加退出条件 return
<body>
<script>
// 函数自己调用自己,称为递归
// 1.利用函数递归打印3句话
let i = 1
function fn() {
console.log(`我是第${i}句话`)
if (i >= 3) return
i++
fn() // 递归
}
fn()
// 2. 练习 利用递归函数实现 setTimeout 每隔一秒钟输出当前时间
function timer() {
const time = new Date().toLocaleString()
console.log(time) // 输出当前时间
setTimeout(timer, 1000) // 函数递归
}
timer()
</script>
</body>
深拷贝思路:
- 深拷贝的核心是利用函数递归
- 封装函数,里面先判断拷贝的是数组还是对象
- 然后开始遍历
- 如果属性值是引用数据类型(比如数组或者对象),则再次递归函数
- 如果属性值是基本数据类型,则直接赋值即可
<body>
<script>
// 递归实现深拷贝 - 简版实现对象和数组的拷贝
const obj = {
name: '佩奇',
family: {
father: '猪爸爸'
},
hobby: ['跳泥坑', '唱歌'],
}
// 封装深拷贝函数 cloneDeep()
function cloneDeep(oldObj) {
// 先判断拷贝的是数组还是对象
const newObj = Array.isArray(oldObj) ? [] : {}
// 遍历拷贝属性和值
for (let k in oldObj) {
// console.log(k) // k 是属性
// console.log(oldObj[k]) // oldObj[k] 是属性值
// 把旧对象的值给新对象的属性
if (typeof oldObj[k] === 'object') {
// 如果属性值是引用数据类型,则需要递归再次拷贝
newObj[k] = cloneDeep(oldObj[k])
} else {
// 否则属性值是基本数据类型,则直接赋值即可
newObj[k] = oldObj[k]
}
}
// 返回新对象
return newObj
}
const newObj = cloneDeep(obj)
newObj.family.father = 'dad'
console.log(newObj)
console.log(obj)
</script>