JavaScript深拷贝的注意事项

  介绍

小编给大家分享一下JavaScript深拷贝的注意事项,希望大家阅读完这篇文章之后都有所收获、下面让我们一起去探讨吧!

之前去一家公司面试的时候,面试官问了我一个问题,说:“如何才能深拷贝一个对象“。当时我心里有些窃喜,这么简单的问题还用想吗?于是脱口而出:“平时常用的有两种办法,第一种用JSON.parse (JSON.stringify (obj)),第二种可以使用的…加递归完成“。面试官听了以后点了点头觉得挺满意的。
当时我也并没有太过在乎这个问题,直到前段时间又想起这个问题,发现上面说的两种方法都是有缺陷的。

提出问题

那么上面所说的缺陷是什么呢?

特殊对象拷贝

首先让我们试想有这么一个对象,在不考虑普通类型的情况下,它有如下成员:

const  obj =, {   ,,,加勒比海盗:,(111,,222),   ,,,obj:,{关键:& # 39;对象& # 39;},   ,,,,,(),=祝辞,{console.log(& # 39;函数& # 39;)},   ,,,日期:,new 日期(),   ,,,reg:,/正则/搞笑   }

然后我们用上面两种方式分别拷贝一次

<强> JSON法

JSON.parse (JSON.stringify (obj))

输出结果:

 JavaScript深拷贝的注意事项

可以从中看出,obj中的普通对象和数组都能拷贝,然而日期对象成了字符串,函数直接就不见了,正则成了一个空对象。
再来看看……在加递归的方法

递归

function  isObj (obj), {   ,,,return  (typeof  obj ===, & # 39;对象# 39;,| |,typeof  obj ===, & # 39;函数# 39;),,,,obj  !==零   }   function  deepCopy (obj), {   ,,,let  tempObj =, Array.isArray (obj), ?, [],:, {}   ,,,(let  key  obj拷贝),{   ,,,,,,,tempObj(例子),=,isObj (obj[主要]),?,deepCopy (obj[主要]),:,obj(例子)   ,,,}   ,,,return  tempObj   }

结果:

 JavaScript深拷贝的注意事项

<强>结论

通过上面的测试可知,这两个方法都无法拷贝函数、日期、注册类型的对象,

<李>

<强>什么是环吗?

环就是对象循环引用,导致自己成为一个闭环,例如下面这个对象:

var  a =, {}      a.a =,

 JavaScript深拷贝的注意事项

使用上面两个方法拷贝一下会直接报错

 JavaScript深拷贝的注意事项

解决方案

<李>

可以使用一个WeakMap结构存储已经被拷贝的对象,每一次进行拷贝的时候就先向WeakMap查询该对象是否已经被拷贝,如果已经被拷贝则取出该对象并返回,将deepCopy函数改造成如下

function  deepCopy (obj, hash =, new  WeakMap ()), {   ,,,如果(hash.has (obj)), return  hash.get (obj)   ,,,let  cloneObj =, Array.isArray (obj), ?, [],:, {}   ,,,hash.set (obj, cloneObj)   ,,,for  (let  key  obj拷贝),{   ,,,,,,,cloneObj(例子),=,isObj (obj[主要]),?,deepCopy (obj(关键),散列),:,obj(例子);   ,,,}   ,,,return  cloneObj   }

拷贝环结果:

 JavaScript深拷贝的注意事项

特殊对象的拷贝

这个问题的解决比较麻烦,因为需要特别对待的对象种类实在太多,于是我参考了MDN上的结构化拷贝,然后结合解决环的方案:

//,只解决日期、注册类型,其他的可以自己添加      function  deepCopy (obj, hash =, new  WeakMap ()), {   ,,,let  cloneObj   ,,,let  Constructor =obj.constructor   ,,,开关(构造函数){   ,,,,,,,case 正则表达式:   ,,,,,,,,,,,cloneObj =, new 构造函数(obj)   ,,,,,,,,,,,休息   ,,,,,,,case 日期:   ,,,,,,,,,,,cloneObj =, new 构造函数(obj.getTime ())   ,,,,,,,,,,,休息   ,,,,,,,默认值:   ,,,,,,,,,,,如果(hash.has (obj)), return  hash.get (obj)   ,,,,,,,,,,,cloneObj =, new 构造函数()   ,,,,,,,,,,,hash.set (obj, cloneObj)   ,,,}   ,,,for  (let  key  obj拷贝),{   ,,,,,,,cloneObj(例子),=,isObj (obj[主要]),?,deepCopy (obj(关键),散列),:,obj(例子);   ,,,}   ,,,return  cloneObj   null

JavaScript深拷贝的注意事项