最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

前端小技巧: TS实现深拷贝函数,考虑 Map, Set, 循环引用

运维笔记admin90浏览0评论

前端小技巧: TS实现深拷贝函数,考虑 Map, Set, 循环引用

前端小技巧: TS实现深拷贝函数,考虑 Map, Set, 循环引用

写一个深拷贝函数

  • 使用 JSON.stringify 和 parse 这类只能适合数据结构简单的,不能循环引用的,没有function的
  • 普通深拷贝
    • 只考虑 Object Array
    • 无法转换 Map Set 和 循环引用
    • 只能应对初级要求的技术一面
function cloneDeep(obj: any) {if (typeof obj !== 'object' || !obj) return objlet result:anyif (obj instanceof Array) {result = []} else {result = {}}for (let key  in obj) {if (obj.hasOwnProperty(key)) {result[key] = cloneDeep(obj[key]) // 递归调用}}return result
}// 不支持的场景
const a: any = {set: new Set([10, 20, 30]),map: new Map(['x', 10], ['y', 20])
}a.self = a // 循环引用 Uncaught RangeError: Maximum call stack size exceeded
console.log(cloneDeep(a)) // 无法处理 Map Set 和 循环引用
  • 上述,对set和map的数据结构不行,会把他们干掉
  • 如果添加循环引用的数据,则直接报错
  • 好的方案如下:
export function cloneDeep(obj: any, map = new WeakMap()): any {if (typeof obj !== 'object' || !obj) return obj// 避免循环引用const objFromMap = map.get(obj)if (objFromMap) return objFromMaplet target: any = {}map.set(obj, target)// Mapif (obj instanceof Map) {target = new Map()obj.forEach((v, k) => {const v1 = cloneDeep(v, map)const k1 = cloneDeep(k, map)target.set(k1, v1)})}// Setif (obj instanceof Set) {target = new Set()obj.forEach(v => {const v1 = cloneDeep(v, map)target.add(v1)})}// Arrayif (obj instanceof Array) {target = obj.map(item => cloneDeep(item, map))}// Objectfor (const key in obj) {const val = obj[key]target[key] = cloneDeep(val, map)}return target
}const a: any = {set: new Set([10, 20, 30]),map: new Map(['x', 10], ['y', 20])
}a.self = a // 循环引用 
console.log(cloneDeep(a))
  • 总结
    • 功能完整性:考虑多种数据结构
    • 鲁棒性,考虑循环引用
    • 能否考虑到如上几点
发布评论

评论列表(0)

  1. 暂无评论