介绍提出问题
小编给大家分享一下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))
输出结果:
可以从中看出,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 }
结果:
<强>结论强>
通过上面的测试可知,这两个方法都无法拷贝函数、日期、注册类型的对象,
- <李>
环
李><强>什么是环吗?强>
环就是对象循环引用,导致自己成为一个闭环,例如下面这个对象:
var a =, {} a.a =,
使用上面两个方法拷贝一下会直接报错
解决方案
- <李>
环
李>可以使用一个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 }
拷贝环结果:
特殊对象的拷贝
这个问题的解决比较麻烦,因为需要特别对待的对象种类实在太多,于是我参考了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 nullJavaScript深拷贝的注意事项