ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javaScript系列 [39]-deepClone

2022-01-03 23:32:26  阅读:169  来源: 互联网

标签:39 console log val javaScript deepClone var 拷贝


本文讨论数据的拷贝,并给出深拷贝的实现代码。

拷贝即复制( copy | clone ),获取指定数据副本的一种行为,理论上我们可以对任意类型的数据进行拷贝,包括但不限于null、undefined、字符串、数字、布尔值、对象、函数、数组、正则表达式等

数据的拷贝,可以具体的分为 浅拷贝 深拷贝 。浅拷贝拷贝一层,副本可能存在共享问题,而深拷贝会拷贝多层,拷贝得到的副本无共享问题。

数据拷贝的方案有很多,譬如可以使用循环遍历和Object.assign()等方法,但这些拷贝方式都是浅拷贝。深拷贝的常见实现方案一种是利用JSON内置对象来进行序列化和反序列化操作,请看下面的代码:

var o = { name: "MiTaoEr", info: { address: "天津", color: "red" } };
var t = JSON.parse(JSON.stringify(o));
o.info.address = "北京";
console.log(t);
/* { name: 'MiTaoEr', info: { address: '天津', color: 'red' } } */

我们先通过JSON.stringify()方法将对象序列化为JSON字符串,然后再进行反序列化的骚操作再转换回来,顺利完成任务。不得不说,这种拷贝对象的方式,手起刀落干净利落,但却有一点点小遗憾,遗憾的是JSON数据中没有函数和 undefined 类型,因此在进行序列化的过程中,对象中的这部分数据会被直接过滤掉,此外正则类型的数据也会被处理为空对象。

var o = { 
  name: "MiTaoEr", 
  ID: undefined, 
  showName: function() {}, 
  reg: /wen/, 
  info: { address: "天津",color: "red" } };

console.log(JSON.parse(JSON.stringify(o)));
/* { name: 'MiTaoEr',reg: {},info: { address: '天津', color: 'red' } } */

利用JSON来实现深拷贝这种实现方式其实不够完美,下面给出通过递归来实现深拷贝的完美方案。

       
<details>
<summary>点击查看代码</summary>

/* 深拷贝实现函数 */
let deepClone = (val, wm = new WeakMap) => {
if (val == null) return val;
if (typeof val !== "object") return val;
if (val instanceof Date) return new Date(val);
if (val instanceof RegExp) return new RegExp(val);
if (wm.has(val)) return wm.get(val);
let _instance = new val.constructor;
wm.set(val, _instance);

for (let key in val) {
if (val.hasOwnProperty(key)) _instance[key] = deepClone(val[key], wm);
}
return _instance;
}

因为`_instance`是引用类型的数据,后续for循环的执行会更新_instance的内容,考虑到循环引用的问题,在`deepClone`方法中用到[ WeakMap ]()类型,其中`wm.set`方法执行后`wm`中保存的数据 `key === value` , 该对象用于数据的记忆。

```javaScript
  /* 001-测试代码:正常情况 */
  //var target = {name: "wen-ding-ding", car:{id: 666 }}
  
  /* 002-测试代码:循环引用 */
  var target = {name: "wen-ding-ding", car:{id: 666 }}
  target.ref = target;
  var result = deepClone(target);

  console.log(target, result);
  console.log(target.ref === result.ref, target.ref === target); /* false true */
  target.car.id = 888;
  console.log(result.car.id); /* 666 */

  /* 003-其它数据类型测试 */
  /* (1) 数组 */
  var arr1 = [100,200,300];
  var arr2 = deepClone(arr1);
  arr1.push(400);
  console.log(arr1,arr2);
  /* [ 100, 200, 300, 400 ] [ 100, 200, 300 ] */

  /* (2) 日期 */
  var date1 = new Date();
  var date2 = deepClone(date1);
  console.log(date1,date2,date1 == date2)
  /* 2019-08-24T11:00:21.379Z 2019-08-24T11:00:21.379Z false*/

  /* (3) null 和 undefined */
  console.log(deepClone(null),deepClone(undefined))
  /* null undefined */

  /* (4) 正则 */
  var reg1 = new RegExp(/\{\{(.+?)\}\}/);
  var reg2 = deepClone(reg1);
  console.log(reg1,reg2,reg1 == reg2)
  /* /\{\{(.+?)\}\}/ /\{\{(.+?)\}\}/ false */

  /* (5) 基本值 */
  console.log(deepClone("wen-ding-ding"),deepClone(2019),deepClone(true))
  /* wen-ding-ding 2019 true */

标签:39,console,log,val,javaScript,deepClone,var,拷贝
来源: https://www.cnblogs.com/wendingding/p/15760925.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有