JavaScript的深拷贝和浅拷贝
一、前言
首先, 我们了解 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 ] }
分类:
JavaScript
标签:
JavaScript
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类