function deepClone(target) { //通过数据创建JSON格式的字符串 let str = JSON.stringify(target); console.log(str); //将JSON字符串转化为JS数据 let data = JSON.parse(str); return data; }
缺点:
function deepClone3(target) { //检测数据类型 if (typeof target !== 'object' || target === null) { // target 是 null ,或者不是对象和数组,说明是原始类型,直接返回 return target; } else { //创建一个容器,存储数组或者对象 const result = Array.isArray(target) ? [] : {}; //遍历target for(let key in target) { //检测该属性是否为对象本身的属性(不能拷贝原型对象的属性) if(target.hasOwnProperty(key)) { //递归遍历子元素,直到能返回原始值 result[key] = deepClone3(target[key]); } } return result; } }
首先要明白map.set()这个方法传入的值是按引用传入的,代码如下:
let result = [1,2,3]; const map = new Map(); map.set(0,result) //这里map.get(0)是[1,2,3] result.push(4); //这里map.get(0)是[1,2,3,4] //综上可以得知map.set()方法传入的值是按引用传入
综上可以得知map.set()方法传入的值是按引用传入。
接下来解决递归版深拷贝无法拷贝循环引用的问题,代码如下
function deepClone3(target,map = new Map()) { //检测数据类型 if (typeof target !== 'object' || target === null) { // target 是 null ,或者不是对象和数组,说明是原始类型,直接返回 return target; } else { //克隆数据前,先进行判断数据之前是否克隆过 let cache = map.get(target); //如果克隆过,直接返回映射中键对应的值,绕开了递归 if(cache) { return cache; } //创建一个容器,存储数组或者对象 const result = Array.isArray(target) ? [] : {}; //将新的结果存入到映射中,克隆目标当键,克隆后结果当值 //注意:map.set()传入的值是按引用传入 map.set(target,result); //遍历target for(let key in target) { //检测该属性是否为对象本身的属性(不能拷贝原型对象的属性) if(target.hasOwnProperty(key)) { result[key] = deepClone3(target[key],map); } } return result; } } //测试用例 const obj1 = { b:['1','2','3'], c: {h: 20} } obj1.b.push(obj1.c); obj1.c.j = obj1.b; const obj2 = deepClone3(obj1)
几个丑字加深理解: