学习目标:
- 掌握深浅拷贝
学习内容:
- 浅拷贝
- 深拷贝
浅拷贝:
开发中我们经常需要复制一个对象。如果直接赋值会有下面问题:
<title>直接复制对象的问题</title>
</head>
<body>
<script>
//一个obj对象
const obj = {
uname: 'pink',
age: 18
}
const o = obj
console.log(o) //{uname: 'pink', age: 18}
o.age = 20
console.log(o) //{uname: 'pink', age: 20}
//但是obj对象里面的age值也发生了变化
console.log(obj) //{uname: 'pink', age: 20}
</script>
</body>
首先浅拷贝和深拷贝只针对引用类型。
- 浅拷贝:拷贝的是地址。
- 常见方法:
- 拷贝对象:
Object.assign( )/ 展开运算符{ ...obj }拷贝对象
。
<title>浅拷贝</title>
</head>
<body>
<script>
const obj = {
uname: 'pink',
age: 18,
family: {
baby: '小pink'
}
}
// 浅拷贝
//1.展开运算符{ ...obj }拷贝对象
// const o = { ...obj }
// console.log(o) //{uname: 'pink', age: 18}
// o.age = 20
// console.log(o) //{uname: 'pink', age: 20}
// console.log(obj) //{uname: 'pink', age: 18}
//另一种方法
//2.Object.assign( )
const o = {}
Object.assign(o, obj)
o.age = 20
//更改对象里面的family还是会有影响
o.family.baby = '老pink'
console.log(o) //{uname: 'pink', age: 20}
console.log(obj) //{uname: 'pink', age: 18}
</script>
</body>
- 拷贝数组:
Array.prototype.concat()或者[...arr]
。
但是还有问题…
<title>浅拷贝</title>
</head>
<body>
<script>
const obj = {
uname: 'pink',
age: 18,
family: {
baby: '小pink'
}
}
// 浅拷贝
//1.展开运算符{ ...obj }拷贝对象
// const o = { ...obj }
// console.log(o) //{uname: 'pink', age: 18}
// o.age = 20
// console.log(o) //{uname: 'pink', age: 20}
// console.log(obj) //{uname: 'pink', age: 18}
//另一种方法
//2.Object.assign( )
const o = {}
Object.assign(o, obj)
o.age = 20
//更改对象里面的family还是会有影响
o.family.baby = '老pink'
console.log(o) //{uname: 'pink', age: 20}
console.log(obj) //{uname: 'pink', age: 18}
</script>
</body>
如果是简单数据类型拷贝值,引用数据类型拷贝的是地址(简单理解:如果是单层对象,没有问题,如果有多层就有问题)。
- 小结:
- 直接赋值和浅拷贝有什么区别?
直接赋值 | 只要是对象,都会相互影响,因为是直接拷贝对象栈里面的地址 |
---|---|
浅拷贝 | 如果是一层对象,不相互影响,如果出现多层对象拷贝还会相互影响 |
- 浅拷贝怎么理解?
拷贝对象之后,里面的属性值是简单数据类型直接拷贝值 | - |
---|---|
如果属性值是引用数据类型则拷贝的是地址 | - |
深拷贝:
- 深拷贝:拷贝的是对象,不是地址。
- 常见方式:
- 通过递归实现深拷贝。
函数递归:
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己,这个函数就是递归函数。
递归函数的作用和循环效果类似。
由于递归很容易发生"栈溢出"错误,所以必须要加退出条件return
。
<title>递归函数</title>
</head>
<body>
<script>
let i = 1
//fn就是递归函数
function fn() {
console.log(`这是第${i}次`)
if (i >= 6) {
return
}
i++
fn() //函数内部调用函数自己
}
fn()
</script>
</body>
- 练习-利用递归函数实现setTimeout模拟setInterval效果。
<title>利用递归函数实现setTimeout模拟setInterval效果</title>
</head>
<body>
<div></div>
<script>
function getTime() {
document.querySelector('div').innerHTML = new Date().toLocaleString()
setTimeout(getTime, 1000) //定时器调用当前函数
}
getTime()
</script>
</body>
- 代码:简版
<title>深拷贝2</title>
</head>
<body>
<script>
const obj = {
uname: 'pink',
age: 18,
hobby: ['跳舞', '弹琴'],
family: {
baby: '小pink'
}
}
const o = {}
//拷贝函数
function deepCopy(newObj, oldObj) {
// k 索引号 oldObj[k] ['跳舞', '弹琴']
for (let k in oldObj) {
//处理数组的问题 一定要先写数组 再写对象 不能颠倒
if (oldObj[k] instanceof Array) {
newObj[k] = []
// newObj[k] 接受[] hobby
//oldObj[k] ['跳舞', '弹琴']
deepCopy(newObj[k], oldObj[k])
} else if (oldObj[k] instanceof Object) {
newObj[k] = {}
// newObj[k] 接受[] hobby
//oldObj[k] ['跳舞', '弹琴']
deepCopy(newObj[k], oldObj[k])
} else {
//k是属性名 uname age
// oldObj[k] 是属性值 18
// newObj[k] === o.uname 属性名
newObj[k] = oldObj[k]
}
}
}
deepCopy(o, obj) //函数调用 两个参数 o是新对象 obj是旧对象
console.log(o) //{uname: 'pink', age: 18}
o.age = 20
o.hobby[0] = '撸猫'
o.family.baby = '大pink'
console.log(obj) //{uname: 'pink', age: 18}
console.log([1, 23] instanceof Object) //true
//复习
// const obj = {
// uname: 'pink',
// age: 18,
// hobby: ['跳舞', '弹琴']
// }
// function deepCopy({ }, oldObj) {
// //k 属性名 oldObj[k] 属性值
// for (let k in oldObj) {
// //处理数组的问题
// newObj[k] = oldObj[k]
// // o.uname = 'pink'
// // newObj.k = 'pink'
// }
// }
</script>
</body>
- js库lodash里面cloneDeep内部实现了深拷贝。
<title>js库lodash里面cloneDeep内部实现了深拷贝</title>
</head>
<body>
<script src="./lodash.min.js"></script>
<script>
const obj = {
uname: 'pink',
age: 18,
hobby: ['跳舞', '弹琴'],
family: {
baby: '小pink'
}
}
//语法:_.cloneDeep(要被克隆的对象)
const o = _.cloneDeep(obj)
console.log(o)
o.family.baby = '老pink'
console.log(obj)
</script>
</body>
- 通过JSON.stringfy()实现。
<title>通过JSON.stringfy()实现</title>
</head>
<body>
<script>
const obj = {
uname: 'pink',
age: 18,
hobby: ['跳舞', '弹琴'],
family: {
baby: '小pink'
}
}
// 把对象转换为 JSON 字符串
// console.log(JSON.stringify(obj))
const o = JSON.parse(JSON.stringify(obj))
console.log(o)
o.family.baby = '123'
console.log(obj)
</script>
</body>
- 小结:
- 实现深拷贝三种方式?
方法 | 说明 |
---|---|
自己利用递归函数书写深拷贝。 | - |
利用js库loadash 里面的_.cloneDeep( ) | const o = _.cloneDeep(obj) |
利用JSON字符串转换 | const o = JSON.parse(JSON.stringify(obj)) |