深拷贝 && 浅拷贝
参考链接:
深拷贝和浅拷贝的区别:
浅拷贝只进行一层复制
,深层次的引用类型还是共享内存地址,原对象和拷贝对象还是会互相影响。
深拷贝无限层级拷贝
,深拷贝后的原对不会和拷贝对象相互影响。
浅拷贝的实现:
Object.assign({}, obj)
arr.slice(0)
[].concat(arr)
Array.from(arr)
[...arr]
、{...obj}
深拷贝的实现:
要求:
- 支持对象、数组、日期、正则的拷贝。
- 处理原始类型(原始类型直接返回,只有引用类型才有拷贝这个概念)。
- 处理Symbol作为键名的情况。
- 处理函数(函数直接返回,拷贝函数没有意义,两个对象使用内存中同一个地址的函数,问题不大)
- 处理DOM元素(DOM元素直接返回,拷贝DOM元素没有意义,都是指向页面中的同一个)
- 额外开辟一个存储空间的WeakMap,解决循环引用递归爆栈问题(引入WeakMap的另一个意义,配合垃圾回收机制,防止内存泄露)
javascript
function deepClone (target, hash = new WeakMap()) { // 额外开启一个空间WeakMap来存储当前对象
if (target === null) return target // 如果是null,不进行拷贝操作
if (target instanceof Date) return new Date(target) // 处理日期
if (target instanceof RegExp) return new RegExp(target) // 处理正则
if (target instanceof HTMLElement) return target // 处理DOM元素
if (typeof target !== 'object') return target // 如果是原始类型和函数,直接返回
// 是引用类型的话就进行深拷贝
if (hash.get(target)) return hash.get(target) // 拷贝当前对象时,先去存储空间中找,如果有直接返回
const cloneTarget = new target.constructor() // 创建一个新的克隆对象或克隆数组
hash.set(target, cloneTarget) // 如果存储空间中国没有就存进hash
// 递归拷贝属性
Reflect.ownKeys(target).forEach(key => { // 引入Reflect.ownKeys,处理Symbol作为键名的情况
cloneTarget[key] = deepClone(target[key], hash) // 递归拷贝每一层
})
return cloneTarget
}
JSON.parse(JSON.stringify(obj))
弊端:
- 忽略undefined、symbol、函数
- NaN、Infinity、-Infinity会被序列化为null
- 无法解决循环引用的问题