深拷贝与浅拷贝
浅拷贝(Shallow Copy)
只复制第一层属性。若属性为基本类型(如number、string),则复制值;若属性为引用类型(如对象、数组),则仅复制引用地址,新旧对象共享该嵌套数据,如果修改嵌套属性会影响原对象
浅拷贝的方法
对象:1.Object.assign({}, obj)。2.扩展运算符{ ...obj }
var a = { count: 1, deep: { count: 2 } } var b = {...a};//扩展运算符 var c = Object.assign({}, a) a.deep.count = 5 console.log(b.deep.count) // 5 console.log(c.deep.count) // 5数组:
arr.slice()截取子数组、浅拷贝,支持负索引(从末尾算起)arr.concat()拼接多个数组/值、浅拷贝,可直接传入非数组元素,自动展开Array.from(arr)类数组转数组、带映射的转换,可传入映射函数,支持thisArg
const arr = [1, 2, 3, 4, 5]; const arr2 = arr.slice(); const arr3 = arr.concat(); const arr4 = Array.from(arr); arr.push(6); console.log(arr);// [1, 2, 3, 4, 5, 6] console.log(arr2); // [1, 2, 3, 4, 5](原数组不变) console.log(arr3); // [1, 2, 3, 4, 5](原数组不变) console.log(arr4); // [1, 2, 3, 4, 5](原数组不变)深拷贝(Deep Copy)
递归复制所有层级,包括嵌套对象和数组;新对象与原对象完全独立,互不影响;修改副本不会影响原对象
深拷贝的方法
1.JSON.parse(JSON.stringify(obj))
简单易用,但无法处理函数、undefined、Symbol、Date、RegExp、循环引用等。使用JSON.stringify和JSON.parse方法时,会丢失对象的原型链、函数以及undefined值
var a = { count: 1, deep: { count: 2 } } var b = JSON.parse(JSON.stringify(a)); a.deep.count = 5; console.log(b.deep.count) // 22.手写递归
这是最常用的方法之一,可以处理大部分数据结构,但需注意处理循环引用。递归方法需要考虑循环引用的问题,通常通过使用WeakMap来记录已拷贝过的对象来解决
function deepCloneWithCycle(obj, map = new WeakMap()) { // 基本类型或 null,直接返回 if (typeof obj !== 'object' || obj === null) { return obj; } // 如果已拷贝过,直接返回缓存结果 if (map.has(obj)) { return map.get(obj); } let result; if (obj instanceof Date) { result = new Date(obj); } else if (obj instanceof RegExp) { result = new RegExp(obj.source, obj.flags); //obj.source:返回该正则表达式的模式字符串(即正则内容本身,不包括斜杠和标志) //obj.flags:返回该正则表达式使用的标志字符串(如 "g"、"i"、"m" 等,或组合如 "gi") } else if (Array.isArray(obj)) { result = []; for (let i = 0; i < obj.length; i++) { result[i] = deepCloneWithCycle(obj[i], map); } } else { result = {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepCloneWithCycle(obj[key], map); } } } // 缓存当前对象的拷贝 map.set(obj, result); return result; } const a = { date: new Date(), deep: { count: 2 } }; const b = deepCloneWithCycle(a); a.deep.count = 5; console.log(b.deep.count) // 23.structuredClone()(推荐用于现代环境)
const a = { date: new Date(), deep: { count: 2 } }; const b = structuredClone(a); a.deep.count = 5; console.log(b.deep.count) // 2