浅拷贝(Shallow Copy):拷贝对象的第一层属性,但如果属性是引用类型(如对象、数组),拷贝的只是其引用地址。
深拷贝(Deep Copy):创建一个新的对象,并递归地复制原对象的所有属性,使得新对象与原对象在内存中完全独立。即修改新对象不会影响原对象。
深拷贝需要考虑的点
- 对象嵌套,即对象的属性也是对象。
- 基本类型。可直接复制,但要注意 new Number(1) 这种对象类型
- symbol 类型。symbol 类型是 JS 中的基本类型,它是唯一且不可变的,无法真正“拷贝”,只能创建新的 Symbol。
- regex 类型。
- 函数。JS 中的函数比较复杂,需要考虑普通函数、箭头函数、闭包、原型方法等情况。
- 循环引用。需要用 Map 存储当前 key/value 对象
- iterable 类型,如 Set、 Map。
实现
浅拷贝
1 | const obj = { a: 1, b: { c: 2 } }; |
修改 obj.b 中的属性同样会影响 copyObj
对于数组复制:
1 | const arrCopy = arr.slice() || const arrCopy = [].concat(arr) |
深拷贝
1.JSON 方式
1 | const obj = { a: 1, b: { c: 2 } }; |
简单,适用于简单对象。但无法拷贝 function、Symbol、undefined、Date、RegExp、Map、Set 等。且会丢失原型链。
2.structuredClone
1 | const obj = { a: 1, b: { c: 2 }, d: new Set([1, 2, 3]) }; |
structuredClone() 是现代浏览器提供的 API,支持 对象、数组、Date、RegExp、Map、Set、Blob、File、ArrayBuffer 等。
但不能拷贝 function、Symbol、原型链。
注意:structuredClone 拷贝不支持的类型,如 Symbol 时,浏览器会报错。
node 17 版本以上才支持。
- messegeChannel
1 | function deepClone(obj) { |
messegeChannel 会建立一个消息通道,并通过两端的端口发送消息实现通信。同样也可以实现深拷贝。
类似于 structuredClone,支持 Date、Set、Map 等类型。不支持 symbol、function
上述提到的 API 都不支持循环引用
4.Lodash 提供了 cloneDeep,是一个经过优化的深拷贝方法,能完美处理大多数情况。
5.简单实现一个 cloneDeep
列举对不同类型的数据的不同处理
1 | // 正则 |