JavaScript的深拷贝和浅拷贝

一、前言

  首先, 我们了解 JavaScript 中的数据类型主要分为:

  基本数据类型:
    NumberStringBooleannullundefinedSymbolBigint

  引用数据类型:
    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() 虽然简单,但是有一些缺陷:

  1. 对象的属性值是函数时,无法拷贝
  2. 原型链上的属性无法拷贝
  3. 不能正确的处理 Date 类型的数据
  4. 不能处理 RegExp
  5. 会忽略 Symbol
  6. 会忽略 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 ] }
posted @   如是。  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类
点击右上角即可分享
微信分享提示