【JavaScript】手写深拷贝 2.0(更新 2022-07-15)

2024前端面试题汇总(持续更新中) 最近一段时间面试才发现真的不背八股文是不得行啊,项目中知道怎么使用怎么写,但是当面试官问你具体含义时,完全是懵的状态,趁着有空刚好总结一下,后续还会继续更新哦。 阅读详情

前言

鄙人老版 js 深拷贝博客链接,当时写的存在很多不足...现在跟着方应杭老师复习了下,收获满满。

用 JSON

const b = JSON.parse(JSON.stringify(a))

缺点:

  1. 不支持 Date、RegExp(正则)、函数等数据;

  2. 不支持引用(即环状结构,类似 window.self = window)。

用递归

基础版

支持 Date、RegExp(正则)、函数等引用数据的拷贝。

const deepClone = (a) => {
  let res = undefined

  // 数据类型判断
  if (a instanceof Object) {
    // 类 判断
    if (a instanceof Function) {
      // 箭头函数判断
      if (a.prototype) {
        // 普通函数
        res = function (...args) {
          return a.call(this, ...args)
        }
      } else {
        // 箭头函数
        res = (...args) => {
          return a.call(undefined, ...args)
        }
      }
    } else if (a instanceof Array) {
      res = []
    } else if (a instanceof Date) {
      res = new Date(a - 0) // 日期格式 - 0 自动转换为时间戳
    } else if (a instanceof RegExp) {
      res = new RegExp(a)
    } else {
      res = {}
    }

    // 递归
    for (let k in a) {
      if (a.hasOwnProperty(k)) {
        res[k] = deepClone(a[k])
      }
    }
  } else {
    res = a
  }
  
  return res
}

测试结果:

image

完整版(支持引用自身的情况)

比如浏览器的 window.self = window,这个时候如果还用上面的拷贝就会导致无限递归导致栈溢出报错。

image

正确的做法是添加一个 map 来记录每次拷贝过的数据,如果出现重复的就不再进行拷贝和递归。(ps:为什么用 map?因为对象 key 值只能为字符串)

const deepClone = (a, cache) => {
  let res = undefined
  if(!cache){
    cache = new Map() // 缓存不能全局,最好临时创建并递归传递
  }

  if (a instanceof Object) {
    // 每次拷贝前判断前面是否已经拷贝过
    // 如果出现 a.self = a 在这里就会返回
    // 防止后续无限递归导致栈溢出
    if (cache.get(a)) {
      return cache.get(a)
    }

    if (a instanceof Function) {
      if (a.prototype) {
        res = function (...args) {
          return a.call(this, ...args)
        }
      } else {
        res = (...args) => {
          return a.call(undefined, ...args)
        }
      }
    } else if (a instanceof Array) {
      res = []
    } else if (a instanceof Date) {
      res = new Date(a - 0)
    } else if (a instanceof RegExp) {
      res = new RegExp(a)
    } else {
      res = {}
    }

    // 每次递归前将拷贝的值就存入 map
    cache.set(a, res)

    for (let k in a) {
      if (a.hasOwnProperty(k)) {
        // 通过参数传递缓存 map
        res[k] = deepClone(a[k], cache)
      }
    }
  } else {
    res = a
  }
  
  return res
}

测试结果:

image

前端面试题(附答案)持续更新中…… 关于前端面试的题,这里整理了一些干货,经常被问到的一些问题,出现频率比较高的问题,如有不足之处,请大家指出,持续更新…(ps一到三颗代表重要性,选择性了解,掌握,前端需要知道的知识)盒模型由内容(content)、内边距(padding)、边框(border)、外边距(margin)组成。盒模型分为IE盒模型和W3C标准盒模型。W3C标准盒模型又叫content-box,元素宽度/高度由border+padding+content组成。(属性width,height只包含内容content,... 阅读详情

相关推荐

CentOS7下Graylog3.0高效日志管理:从零搭建到实战应用

本文详细介绍了在CentOS7操作系统上从零开始搭建Graylog3.0日志管理平台的完整过程。内容涵盖Java环境准备、MongoDB与Elasticsearch依赖安装、Graylog Server核心配置,并实战演示了通过Graylog Sidecar集中管理日志采集器以及配置邮件告警功能,为中小型团队提供了一个比ELK更轻量、易维护的一体化日志解决方案。

weixin_29207149的博客 85

【2025前端面试题总结】JS手写代码篇

前端面试题 - JS 手写代码

2301_76769195的博客 1880

从零开始:手把手教你检查并更新英伟达GPU驱动和CUDA版本(Windows/Linux双平台)

本文详细指导如何在Windows和Linux系统上检查并更新英伟达GPU驱动和CUDA版本,解决版本不匹配导致的常见问题。涵盖驱动更新、CUDA Toolkit安装、版本冲突排解及性能优化技巧,帮助开发者高效管理GPU计算环境。

weixin_29237635的博客 701

JavaScript 中十种数组拷贝方法(从浅拷贝到深拷贝)

本文全面介绍了JavaScript中的数组拷贝方法,分为浅拷贝和深拷贝两大类。浅拷贝方法包括扩展运算符、for/while循环、map/filter/reduce方法、slice/concat/Array.from等,适用于简单数组场景。深拷贝方法主要介绍了JSON.parse/stringify和自定义递归函数两种方式,后者能更好地处理复杂对象和循环引用。文章通过代码示例详细演示了每种方法的实现和特性,并对比了不同深拷贝方法的优缺点,帮助开发者根据实际需求选择最合适的数组拷贝方案。

小猫三两只。 1287

springboot+shardingsphere+druid 实现基于时间的水平分表

使用shardingsphere基于时间字段的动态水平分片。

weixin_42207940的博客 2626

保姆级教程:用QSTEM和DrProbe搞定你的第一张STEM模拟图(附Fe3O4实例文件)

本文提供了一份详细的STEM模拟图像生成教程,涵盖从晶体结构获取到最终图像模拟的全过程。通过QSTEM和DrProbe软件的操作指南,帮助材料科学研究者快速掌握STEM模拟技术,特别适合初学者。教程包含Fe3O4实例文件,详细解析参数设置、计算优化和结果分析等关键步骤。

weixin_33730836的博客 523

手写js的方法,持续更新

每天至少一个手写方法,简略实现javascript的一些内置方法,有问题请指出~~~ extend function _extends(...arg) { const res = {}; for (let index = 0; index < arg.length; index++) { const obj = arg[index]; for (const v in obj) { if (Object.hasOwnProperty.call(obj, v)) {

qq_38160125的博客 315

Windows11安装UE4+Airsim

Windows11安装UE4+Airsim

Legendyyy的博客 3743

【JavaScript】浅拷贝和深拷贝

Javascript浅拷贝与深拷贝

Jerryqjr的博客 483

YOLO26 网络结构逐模块解析:Backbone/Neck/Head

本文解析了YOLO26目标检测网络的架构设计,重点介绍其在Backbone、Neck和Head三个核心组件的创新优化。Backbone采用改进的CSP模块与轻量级注意力机制,提升特征提取效率;Neck使用改进的BiFPN结构实现高效多尺度特征融合;Head采用完全解耦设计简化回归流程。文章详细分析了各模块的技术演进、实现细节和设计思想,通过流程图和代码示例展示了YOLO26的整体架构和关键组件实现。该研究对模型优化、定制开发和硬件部署具有重要指导意义。

一键难忘的博客 1241

在 FlexSim 中建 AGV 小车模型时,如果设定“每次充电需要 2 小时才能充满”,应该如何配置 AGV 的充电功能?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值。

**My Coding Family** 880

「offer来了」保姆级巩固你的js知识体系(4.0w字)

「面试集锦」前端面试之JavaScript篇序言文章内容抢先看一、JS规范1、说几条JavaScript的基本规范。2、对原生JavaScript的了解。3、说下对JS的了解吧。4、JS原生拖拽节点5、谈谈你对ES6的理解6、知道ES6的class嘛?7、说说你对AMD和Commonjs的理解8、如何理解前端模块化9、面向对象编程思想10、用过 TypeScript 吗?它的作用是什么?11、PWA使用过吗?serviceWorker的使用原理是啥二、数据类型1、问:0.1

moandaylab 4632

汽车电子零部件(14):TMS热管理系统

TMS(thermal management system)热管理系统,这是新能源汽车诞生后随之而产生的一种新汽车零部件,一旦热管理失控会触发自燃,这种现象也是对EV来说是件头疼的事。汽车的热管理系统(TMS)是一个关键部件,有助于调节汽车电池组、车厢和其他车辆系统的温度。TMS的主要目的是在驾驶过程中保持最佳的电池性能和乘客舒适度。TMS使用各种加热和冷却系统来调节电池组和车厢的温度,并通过优化其使用,降低能耗,提高车辆的整体效率。

码农17年的博客 3161

js 小知识 持续更新

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 js 小知识 持续更新使用步骤01-检查日期是否为周末02-获取数组中的唯一值(数组去重)03-检查变量是否为数组04-获取javascript语言的实际类型05-在结尾处截断字符串06-从中间截断字符串总结 使用步骤 01-检查日期是否为周末 代码如下(示例): const isWeekend = (date) => [0, 6].indexOf(date.getDay()) !== -1; console.log(isWee.

weixin_44690999的博客 541

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

手撕js,不说一句话搞定一场面试

目录1.手写Promise2. 手写一个深拷贝函数3. 手写一个防抖函数4. 手写一个节流函数5. 手写bind()6. 手写call()7. 手写apply()8. 手写bind()9. 数组扁平化10. 自定义消息订阅与发布11. 手写axios函数12. 自定义事件总线13.自定义new工具函数14. 如何在 JS 中“深冻结”对象1. 没有深冻结2. 深冻结15. 自定义数组声明式系列方法1. map()方法实现2. 实现reduce()3.实现filter()4.实现find()5.实现find

田兴的博客 1410

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

前端javaScript高频面试题——持续更新

前端javaScript高频面试题

m0_63873004的博客 496

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

JavaScript【工具函数助力高效开发】

JavaScript【工具函数助力高效开发】

商务合作/软件定制/学习交流 1036

前端开发知识汇总--JS

前言 本文主要从JS以及一些好玩的demo,做一个汇总,会不定期地更新。。 JS 數組切片 js切片,将一维数组,切成n组长度3的二维数组 var a = [1, 2, 3, 4, 5, 6, 7, 8] var result = [] function slice(l) { do { var newarr = l.splice(0, 3); reult.push(newa...

j_bleach的博客 2053

JavaScript面试题看这一篇就够了(持续更新......)

JavaScript经典面试题 1.简要描述 JS 的数据类型? 答案:JavaScript 的数据类型可分为原始数据类型和引用数据类型。 原始数据类型:String(字符串)、Number(数字)、Boolean(布尔)、Null(空)、Undefined(未定义) 引用数据类型:Array(数组)、Object(对象)、Function(函数) 2.看代码,写出结果 var a = []; ...

Hassan的小博客! 861

【每日一练】前端面试题集锦2

【每日一练】前端面试题集锦2, 基础知识(2vue + 2js + 2css) + 数据结构算法(链表中等题/深度优先搜索/链表/双链表)

Tomorrow belongs to those who prepare for it today. 1413

2022年,前端web最新面试题,持续更新中.....

面试必问之一,

Y974066017的博客 732

牛客JS题(十七)总成绩排名

注释很详细,直接上代码……

https://github.com/amoorzheyu 1075

前端面试——JavaScript面经(持续更新)

本文记录为了面试而总结的JavaScript面经,其中包括JavaScript用哪些数据类型、它们有什么区别、判断数组的方式有哪些?、null和undefined有什么区别?等等

weixin_43599321的博客 2677

JS爬虫逆向

JavaScript爬虫逆向是现代网络数据采集的重要组成部分,适合面对动态内容和复杂数据加载的网站。理解其原理及操作流程,将使开发者能够更有效地获取、分析和利用数据,为决策提供有力支持。

starry-sea1412的弃坑之路 2129

2024年最新前端面试题——你也可以成为那个卷王(持续更新中~)

2023年最新前端面试题,每天几道你便能轻松进入大厂,成为卷中之王!!!

每天一个前端小知识~ 3万+

2024前端面试总结—JS篇(文档持续更新中。。。)

2024前端面试总结—JS篇(文档持续更新中。。。)

河面下的少年的博客 1148
上一篇: 【设计模式】JavaScript 手写发布订阅
下一篇: 【JavaScript】内存管理和垃圾收集机制
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值