手写【深拷贝】

news2024/11/21 2:27:26

JS中深拷贝的实现

  • JSON.parse(JSON.stringify())
  • 递归实现深拷贝

使用JSON.parse(JSON.stringify()) 实现 无法拷贝 函数正则时间格式原型上的属性和方法

递归实现深拷贝

es5实现深拷贝

  • 源对象
const obj = {
    name: '张桑',
    age: 18,
    hobby: [
      {
        name: '篮球',
        year: 5,
        loveStar: ['Luka', 'Curry', 'Dragic']
      }
    ],
    run: function () {
      return 'xxxx'
    }
  }
  • deepClone实现
// 深拷贝(es5实现)
function deepClone (origin, target) {
  // 1.判断传入的origin 是否存在
  var tar = target || {}
  // 5.toString是 object对象原型上的方法 Object.prototype.toString.call({}) => [object Object]
  var toStr = Object.prototype.toString
  var arryType = '[obeject Array]'
  // 2.遍历对象
  for (var k in origin) {
    // 4.这里不能拷贝其原型上的属性
    if (origin.hasOwnProperty(k)) {
       // 3.判断k是否为对象 且不能为null  typeof null === 'object'
      if (typeof origin[k] === 'object' && origin[k] !== null) {
        // 6. 这里已经判断origin[k] 是object 只需要判断是{} 还是 []
        tar[k] = toStr.call(origin[k]) === arryType ? [] : {}
        deepClone(origin[k], tar[k])
      } else {
        tar[k] = origin[k]
      }
    }
  }
  return tar
}
const newObj = deepClone(obj, {})
obj.age = 19
console.log(newObj)

实现思路
1. 先判断传入的origin是否存在
2. 存在就遍历该对象
3. 通过hasOwnProperty(k)判断是否是其原型上的属性,不拷贝其原型上的属性
4. 判断k是否为对象 且不能为null typeof null === 'object'
5. 通过是 object对象原型上的方法 toString 判断k是{} 还是[]

Object.prototype.toString.call({})  // '[object Object]'
Object.prototype.toString.call([])  // '[object Array]'

6.再进行递归拷贝deepClone(origin[k], tar[k])

es6实现深拷贝


// null undefined 和 不是对象的数据 直接返回  
// 封装一个判断方法
function isObject(origin) {
  return typeof origin === "object" && origin !== null;
}
function deepClone (origin) {
  if (!isObject(origin)) return origin
  // 还需要考虑的 Date RegExp 等 可以通过instanceof 判断其构造函数
  if (origin instanceof Date) {
    return new Date(origin)
  }
  if (origin instanceof RegExp) {
    return new RegExp(origin)
  }
  // 处理 {} []
  // 通过构造器判断它是否为对象、 数组
  /**
   * const obj = {}
   * const newObj = new obj.constructor() // 相当于拷贝了origin
   * 这样就不需要判断origin是对象还是数组
  */
  const target = new origin.constructor()
  for (let k in origin) {
    if (origin.hasOwnProperty(k)) {
      target[k] = deepClone(origin[k])
    }
  }
  return target
}
const newObj = deepClone(obj)
console.log(newObj)
let target = {name: 'target'}; 
target.target = target
const newObj = deepClone(target)
console.log(newObj)

实现思路

  1. 这里首先封装了一个方法用来 nullundefined 和 不是对象的数据,这些数据直接可以返回
	function isObject(origin) {
	  return typeof origin === "object" && origin !== null;
	}
	// deepClone中判断
	if (!isObject(origin)) return origin
  1. 针对DateRegExp 等 可以通过instanceof 判断其构造函数来区分,做特殊处理。
	 if (origin instanceof Date) {
	    return new Date(origin)
	  }
	  if (origin instanceof RegExp) {
	    return new RegExp(origin)
	  }
  1. es5方法中是通过是 object对象原型上的方法 toString 判断k是{} 还是[],这里可以使用new 其对象的构造方法则不需要判断origin是对象还是数组
 const target = new origin.constructor() // 相当于拷贝了origin
  1. 遍历origin,递归拷贝origin[k]

使用WeakMap优化

问题

  1. 循环拷贝(对象的属性引用自己) 问题
    使用上面es6 的deepClone方法,直接栈溢出了
let target = {name: 'target'}; 
target.target = target
const newObj = deepClone(target)
console.log(newObj)

在这里插入图片描述
2. 重复拷贝(对象的属性引用同一个对象) 问题

let obj = {}; 
let target = {a: obj, b: obj};

这里拷拷贝a的时候拷贝了obj,拷贝b的时候又拷贝了一次

// 深拷贝 (WeakMap)
// 1. 解决循环拷贝(对象的属性引用自己)  问题
// 2. 解决重复拷贝(对象的属性引用同一个对象) 问题
// WeakMap 防止内存泄漏  键名如果外部没有引用,键值键名就会被内存回收掉
function isObject(origin) {
  return typeof origin === "object" && origin !== null;
}
function deepClone (origin, hashMap = new WeakMap()) {
  if (!isObject(origin)) return origin
  // 还需要考虑的 Date RegExp 等 可以通过instanceof 判断其构造函数
  if (origin instanceof Date) {
    return new Date(origin)
  }
  if (origin instanceof RegExp) {
    return new RegExp(origin)
  }

  const hashKey = hashMap.get(origin)
  if (hashKey) {
    return hashKey
  }
  // 处理 {} []
  // 通过构造器判断它是否为对象、 数组
  /**
   * const obj = {}
   * const newObj = new obj.constructor() // 相当于拷贝了obj
   * 这样就不需要判断origin是对象还是数组
  */
  const target = new origin.constructor()
  hashMap.set(origin,target)
  for (let k in origin) {
    if (origin.hasOwnProperty(k)) {
      target[k] = deepClone(origin[k], hashMap)
    }
  }
  return target
}
let target = {name: 'target'}; 
target.target = target
const newObj = deepClone(obj)
console.log(newObj)

实现思路
这里给deepClone 方法加了一个参数,默认是new WeakMap(),利用WeakMap键名如果外部没有引用,键值键名就会被内存回收掉的特性,记录origin是否被拷贝过,拷贝过则直接返回

  const hashKey = hashMap.get(origin) // 查询是否有origin这个键
  if (hashKey) {
    return hashKey
  }
  
  hashMap.set(origin,target) // 拷贝前将其存起来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/491575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

极简爬虫通用模板

网络爬虫的一般步骤如下: 1、确定爬取目标:确定需要爬取的数据类型和来源网站。 2、制定爬取策略:确定爬取哪些网页、如何爬取和频率等。 3、构建爬虫程序:使用编程语言(如Python)实现爬虫程序&#xff…

【python】列表、字典、元组与集合的特点以及对比

一、列表(List) 1. 列表的特点 数据按顺序存储列表有正序、倒序两种索引列表可存储任意类型的数据,并且允许重复。 2. 列表的遍历: lst[1,2,3] for i in range(len(lst)):print(lst[i],end" ")3. 列表的缺点&#x…

虹科方案 | HK-TrueNAS:音频协作的理想存储

一、虹科HK-TRUENAS 非常适合 AVID PRO TOOLS™ 专业音频编辑和大多数媒体和娱乐 (M&E) 工作流程从录制开始,经过后期制作,最后进入播放。这一过程可能需要几个月的时间来拍摄一部大型的电影,也可能需要几个小时甚至几分钟的时间来播放最…

Java电子招投标采购系统源码-适合于招标代理、政府采购、企业采购、工程交易等业务的企业

招投标管理系统-适合于招标代理、政府采购、企业采购、工程交易等业务的企业 招投标管理系统是一个用于内部业务项目管理的应用平台。以项目为主线,从项目立项,资格预审,标书编制审核,招标公告,项目开标,项…

使用篇丨链路追踪(Tracing)很简单:链路拓扑

作者:涯海 最近一年,小玉所在的业务部门发起了轰轰烈烈的微服务化运动,大量业务中台应用被拆分成更细粒度的微服务应用。为了迎接即将到来的双十一大促重保活动,小玉的主管让她在一周内梳理出订单中心的全局关键上下游依赖&#…

反射~~~

文章目录 反射反射获取Class类对象反射获取构造器对象反射获取成员变量对象反射获取方法对象反射的作用绕过编译阶段为集合添加数据通用框架的底层原理 反射 反射获取Class类对象 getClass()方法为Object类中的成员方法 反射获取构造器对象 parametTypes为参数的类对象 获得类的…

智安网络|网络安全威胁越来越多,教你如何全方面应对

随着互联网的普及和发展,各大网站已经成为人们获取信息和交流的主要平台。然而,随着网络攻击和恶意软件的威胁不断增加,网站经常成为攻击者的目标。因此,在建立和维护网站系统时,必须采取强大的安全措施。 一、网站系…

阅读有感重庆rcgl

1.json转为对应的泛型集合 List<String> resourceList JSON.parseArray(JSON.toJSONString(obj), String.class); 2.集合转换为数组 String[] roles (String[])resourceList.toArray(new String[0]); 3.json转换为对应的javabean SLoginRule loginRule (SLoginRul…

【Web项目实战】从零开始学习Web自动化测试:用Python和Selenium实现网站登录功能

B站首推&#xff01;2023最详细自动化测试合集&#xff0c;小白皆可掌握&#xff0c;让测试变得简单、快捷、可靠https://www.bilibili.com/video/BV1ua4y1V7Db 目录 1.环境搭建 2.编写测试用例 3.运行测试用例 3.1 命令行方式 3.2 集成到CI/CD流程中 4.结论 Web自动化测…

Windows安装配置Tomcat服务器教程 ——外网远程访问

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 转载自cpolar文章&#xff1a;外网访问本地Tomcat服务器【cpolar内网穿透】…

ReadTimeoutError: HTTPSConnectionPool(host=‘files.pythonhosted.org‘, port=443)

问题&#xff1a; 今天在遇到了安装pytorch中的torchvision包的时候一直超时失败报错如下 ReadTimeoutError: HTTPSConnectionPool(hostfiles.pythonhosted.org, port443): Read timed out. 之前的安装的方式是&#xff1a; pip install --no-deps torchvision 解决办法&…

uni——模拟购物车(全选、全不选、步进器、结算等)

案例演示 案例代码 <template><pageBox ref="pagebox"><view class=

Java程序设计入门教程--案例:自由落体

程序模拟物体从10000米高空掉落后的反弹行为。 球体每落地一次&#xff0c;就会反弹至原高度的一半。按用户输入的弹跳次数&#xff0c;计算球体每次弹跳的高度。 实现过程&#xff1a; 1. 新建项目&#xff1b; 2. 接收 用户输入的弹跳次数&#xff1a; &#xff08;1&#…

通过Robotstudio修改机器人程序的具体方法和步骤

通过Robotstudio修改机器人程序的具体方法和步骤 基本步骤可参考以下内容: 用网线连接机器人和电脑,机器人一侧要插入LAN2口;机器人和电脑的IP地址要在同一个网段内;请求写入权限;修改程序—编译—应用;加载修改后的程序到机器人;保存Robotstudio程序到电脑端;只能修改…

超大规模视觉通用感知模型

超大规模视觉通用感知模型 通用感知模型简介与发展超大规模图像、文本主干网络多任务兼容解码网络 参考文献 通用感知模型简介与发展 通用感知模型是指一个模型解决不同的感知任务&#xff0c;应用于各种模态数据。 通用感知模型的发展脉络图如下&#xff0c;它由NLP发源&…

Visual Studio Code 和 GitHub Copilot

翻译自 Chris Dias 的博客 AI 这个话题&#xff0c;近期我们看到它被大家广泛地谈论&#xff0c;有些人很兴奋&#xff0c;也有些人表达了担忧。进步几乎每天都在发生&#xff0c;速度前所未有。每天有超过一百万的 Copilot 用户&#xff0c;如果你有机会尝试&#xff0c;你可…

简易英文统计和加密系统的设计实现(纯C语言实现,包含文件操作、注释多、易理解)

❤️作者主页&#xff1a;微凉秋意 &#x1f525;系列专栏&#xff1a;数据结构与课程设计 ✅作者简介&#xff1a;后端领域优质创作者&#x1f3c6;&#xff0c;CSDN内容合伙人&#x1f3c6;&#xff0c;阿里云专家博主&#x1f3c6; 文章目录 前言部分功能、开发环境与项目结…

十二、模块化开发

一、什么是模块化&#xff1f; 到底什么是模块化、模块化开发呢&#xff1f; 事实上模块化开发最终的目的是将程序划分成一个个小的结构&#xff1b;这个结构中编写属于自己的逻辑代码&#xff0c;有自己的作用域&#xff0c;定义变量名词时不会影响到其他的结构&#xff1b;…

上海车展:油电反转,新能源车竞争白热化

还记得2009年的上海车展&#xff0c;新能源车初来乍到&#xff0c;一共才展出47辆&#xff0c;占所有展出车辆5.12%&#xff0c;今年参展车型中&#xff0c;传统燃油车型有58款&#xff0c;新能源车有76款&#xff0c;新能源车第一次超过燃油车&#xff0c;实现油电反转。 电动…

均值滤波 附带简易code

1.概念介绍  均值滤波是典型的 线性滤波算法&#xff0c;是指用当前像素点周围nxn个像素值的均值来代替当前像素值。使用该方法遍历处理图像内的每一个像素点&#xff0c;可完成整幅图像的均值滤波。 2.基本原理  如图2-1&#xff0c;我们对第5行第5列的像素点进行均值滤波时…