一、前言
首先, 我们了解 JavaScript 中的数据类型主要分为:
基本数据类型:
Number
、 String
、 Boolean
、 null
、 undefined
、 Symbol
、 Bigint
引用数据类型:
Object
其中,引用数据类型的值是保存在栈内存和堆内存中的对象,栈区保存变量的标识符和指向堆内存该对象的指针。当使用引用值时,解析器会先往栈区寻找地址,然后根据地址找到堆内存中的实体。
二、浅拷贝
先说浅拷贝,浅拷贝就是只拷贝对象的表层,如果内部数据有对象或数组,那么只会拷贝到该属性在栈中的地址。
新旧数据此时引用的是同一片数据,只要一个改变就都会改变。
let stu = {
name: '小红',
age: 108,
bestFriend: {
name: '小军',
age: 26,
},
}
// 通过函数拷贝
function copyObject(obj) {
let newObj = {}
for (let i in obj) {
newObj[i] = obj[i]
}
return newObj
}
let newObj_1 = copyObject(stu)
// 通过拓展运算符拷贝
let newObj_2 = {
...stu
}
// 先输出查看数据
console.log(stu) // { name: '小红', age: 108, bestFriend: { name: '小军', age: 26 } }
console.log(newObj_1) // { name: '小红', age: 108, bestFriend: { name: '小军', age: 26 } }
console.log(newObj_2) // { name: '小红', age: 108, bestFriend: { name: '小军', age: 26 } }
console.log('----------------------------')
// 修改源数据的表层数据:源数据改变不影响拷贝出来的数据
stu.name = '张三'
console.log(stu) // { name: '张三', age: 108, bestFriend: { name: '小军', age: 26 } }
console.log(newObj_1) // { name: '小红', age: 108, bestFriend: { name: '小军', age: 26 } }
console.log(newObj_2) // { name: '小红', age: 108, bestFriend: { name: '小军', age: 26 } }
console.log('----------------------------')
// 修改源数据的里层数据: 一个改变其余跟着改变
stu.bestFriend.name = '李四'
console.log(stu) // { name: '张三', age: 108, bestFriend: { name: '李四', age: 26 } }
console.log(newObj_1) // { name: '小红', age: 108, bestFriend: { name: '李四', age: 26 } }
console.log(newObj_2) // { name: '小红', age: 108, bestFriend: { name: '李四', age: 26 } }
三、深拷贝
深拷贝不像浅拷贝那样只拷贝一层,而是层层拷贝。
新旧数据是完全分离的, 互不影响, 修改一个不会影响另一个
3.1 通过递归实现深拷贝
只是实现一个简单的深拷贝, 不是最佳
let stu = {
name: '小红',
age: 108,
bestFriend: {
name: '小军',
age: 26,
},
arr: [0, 1]
}
function copyObject(obj) {
let newObj = null
if (obj instanceof Array) {
newObj = []
} else {
newObj = {}
}
// 拷贝的算法
for (let i in obj) {
// newObj[i] = obj[i]
// 在浅拷贝代码的基础上,在这里添加判断
// 如果某一项是一个引用类型,就递归调用拷贝的这个函数
if (obj[i] instanceof Object) {
newObj[i] = copyObject(obj[i])
} else {
newObj[i] = obj[i]
}
}
return newObj
}
let newObj = copyObject(stu)
// 修改源数据的浅层数据、深层对象中的数据、深层数组中的数据
stu.name = '小刚'
stu.bestFriend.name = '李四'
stu.arr.push(3)
console.log(stu)
console.log(newObj)
// { name: '小刚', age: 108, bestFriend: { name: '李四', age: 26 }, arr: [ 0, 1, 3 ] }
// { name: '小红', age: 108, bestFriend: { name: '小军', age: 26 }, arr: [ 0, 1 ] }
3.2 通过 JSON.parse 实现深拷贝
注意:
JSON.parse() 虽然简单,但是有一些缺陷:
- 对象的属性值是函数时,无法拷贝
- 原型链上的属性无法拷贝
- 不能正确的处理 Date 类型的数据
- 不能处理 RegExp
- 会忽略 Symbol
- 会忽略 undefined
let stu = {
name: '小红',
age: 108,
bestFriend: {
name: '小军',
age: 26,
},
arr: [0, 1],
}
function copyObject(obj) {
let newStr = JSON.stringify(obj)
let newObj = JSON.parse(newStr)
return newObj
// 上面三行可以简化为:
// return JSON.parse(JSON.stringify(obj))
}
let newObj = copyObject(stu)
// 修改源数据的浅层数据、深层对象中的数据、深层数组中的数据
stu.name = '小刚'
stu.bestFriend.name = '李四'
stu.arr.push(3)
// 查看新旧数据是否发生变化
console.log(stu)
console.log(newObj)
// { name: '小刚', age: 108, bestFriend: { name: '李四', age: 26 }, arr: [ 0, 1, 3 ] }
// { name: '小红', age: 108, bestFriend: { name: '小军', age: 26 }, arr: [ 0, 1 ] }
标签:bestFriend,name,age,JavaScript,newObj,stu,拷贝
From: https://www.cnblogs.com/bkzj/p/16801229.html