一、浅拷贝
创建一个新对象,对源对象的属性进行拷贝,两者共享同一个内存地址。只拷贝第一层属性,如果属性是引用类型(如对象、数组),不会递归复制,而是复制引用地址。
1.常用方法
方法 | 说明 |
Object.assign() | 将源对象的属性复制到目标对象 |
展开运算符 ... | 简洁语法,浅拷贝对象或数组 |
arr.slice() | 浅拷贝数组的一种常见方式 |
arr.concat() | 合并数组时也可实现浅拷贝 |
Object.create() | 创建一个对象并设置原型(非严格意义上的浅拷贝) |
2.使用案例
// 案例1:
var obj = {a:1}
var obj2=Object.create(obj) // 创建对象
obj2.a=2
console.log(obj ===obj2) // false
console.log(obj.a,obj2.a) // 2 2
// 案例2:
var obj = {a:1,b:{c:1}}
var obj2=Object.assign({},obj) // 合并对象属性。 {...obj}同理
obj.a = 2
obj.b.c= 2
console.log(obj === obj2) // false
console.log(obj,obj2) // obj = {a:2,b:{c:2}}
// obj2 = {a:1,b:{c:2}} 其中基本数据类型没有改变,引用数据类型改变了
二、深拷贝
创建一个新对象,新对象和原始对象的属性完全相同但是指向不同的地址,修改其中一个不会影响另外一个。拷贝所有层级。
1.常用方法
方法 | 说明 |
JSON.parse(JSON.stringify(obj)) | 适用于纯数据对象(无函数/undefined/循环引用) 缺点: 会丢失:函数、undefined、Symbol 无法处理:循环引用 时间对象(Date)会变成字符串 |
cloneDeep(obj) | 使用第三方库Lodash的cloneDeep:可靠、高性能、支持循环引用、各种边界情况 缺点:引入第三方库,体积略大(可做按需引入) |
手写深拷贝函数 | 递归遍历拷贝,可处理循环引用、复杂嵌套,不会丢函数、Symbol 优点: 可处理循环引用、复杂嵌套 不会丢函数、Symbol 缺点:代码复杂、性能一般 |
structuredClone(obj) | 现代浏览器中的原生 API,支持循环引用、Map、Set、Date 等,高性能、现代浏览器支持良好 缺点: 不支持函数、DOM 节点 Node.js 需 v17+ 开启 -experimental |
2.使用案例
// 1.JSON方法
// JSON.stringify():**序列化,将对象转为JSON字符串
// JSON.parse():**反序列化,将JSON字符串转为对象
var obj2 = JSON.parse(JSON.stringify(obj))
// 2.使用第三方库Lodash的cloneDeep
import cloneDeep from 'lodash/cloneDeep'
const clone = cloneDeep(obj)
// 3.手写深拷贝函数
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj
if (map.has(obj)) return map.get(obj)
const clone = Array.isArray(obj) ? [] : {}
map.set(obj, clone)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], map)
}
}
return clone
}
// 4.使用 structuredClone(现代浏览器)
const clone = structuredClone(obj)