使用const data = JSON.parse(JSON.stringify(x))
完成的深拷贝
可解决大部分情况下深拷贝需求,但不支持Date、正则、undefined、函数等数据,且不支持引用。
所以此时需要一个更完备的深拷贝方法。
先上最终代码
const cache = new Map() function deepClone(obj){ if(typeof obj !== 'object' || obj === null) return obj; if(cache.get(obj)){ return cache.get(obj) } let result = {} if(obj instanceof Function){ // 不能100%拷贝 if(obj.prototype){ result = function(){ return obj.apply(this,arguments) } }else{ result = (...args) => a.call(undefined, ...args) } } if(obj instanceof Array){ result = [] } if(obj instanceof Date){ result = new Date(obj - 0) } if(obj instanceof RegExp){ result = new RegExp(obj.source, obj.flags) } cache.set(obj, result) for(let key in obj){ result[key] = deepClone(obj[key]) } return result } // 测试数据 const obj1 = { number:1, bool:false, str: 'hi', empty1: undefined, empty2: null, array: [ {name: 'hy', age: 18}, {name: 'jacky', age: 19} ], date: new Date(2000,0,1,20,30,0), regex: /\.(j|t)sx/i, obj: { name:'frank', age: 18}, f1: (a, b) => a + b, f2: function(a, b) { return a + b } } obj1.self = obj1 const obj2 = deepClone(obj1) obj1.array[0] = 'xxx'
基本实现
// 创建函数 function deepClone(obj){ // 创建返回值变量 let result = {} return result }
function deepClone(obj){ /* 其他代码 */ //传参不为对象 直接return if(typeof obj !== 'object' || obj === null) return obj; /* 其他代码 */ }
function deepClone(obj){ /* 其他代码 */ // 传参为函数 if(obj instanceof Function){ // 不能100%拷贝 //普通函数 if(obj.prototype){ result = function(){ return obj.apply(this,arguments) } }else{ //箭头函数 result = (...args) => a.call(undefined, ...args) } } /* 其他代码 */ }
function deepClone(obj){ /* 其他代码 */ // 传参为数组 if(obj instanceof Array){ result = [] } /* 其他代码 */ }
function deepClone(obj){ /* 其他代码 */ // 传参为日期 if(obj instanceof Date){ // obj为日期时,则格式如 -> Sun Jun 19 2022 20:03:03 GMT+0800 (中国标准时间) // obj - 0 则得到此时间戳 -> 1655640152585 // 再将此时间戳赋予到new Date中 result = new Date(obj - 0) } /* 其他代码 */ }
function deepClone(obj){ /* 其他代码 */ // 传参为正则 if(obj instanceof RegExp){ result = new RegExp(obj.source, obj.flags) } /* 其他代码 */ }
function deepClone(obj){ /* 其他代码 */ // 基本赋值 for(let key in obj){ // 有些属性是继承,有些属性是自身,我们只遍历自身属性 if(obj.hasOwnProperty(key)){ // 直接赋值是不行的,因为obj[key]也有可能是对象,直接赋值就变成了浅拷贝 // result[key] = obj[key] // 正确写法,赋值前调用深拷贝方法,如果是普通类型则不变,如果为对象类型则进行深拷贝。 result[key] = deepClone(obj[key]) } } /* 其他代码 */ }
基本完成
function deepClone(obj){ if(typeof obj !== 'object' || obj === null) return obj; let result = {} if(obj instanceof Function){ // 不能100%拷贝 if(obj.prototype){ result = function(){ return obj.apply(this,arguments) } }else{ result = (...args) => a.call(undefined, ...args) } } if(obj instanceof Array){ result = [] } if(obj instanceof Date){ result = new Date(obj - 0) } if(obj instanceof RegExp){ result = new RegExp(obj.source, obj.flags) } for(let key in obj){ if(obj.hasOwnProperty(key)){ result[key] = deepClone(obj[key]) } } return result } // 测试数据 const obj1 = { number:1, bool:false, str: 'hi', empty1: undefined, empty2: null, array: [ {name: 'frank', age: 18}, {name: 'jacky', age: 19} ], date: new Date(2000,0,1,20,30,0), regex: /\.(j|t)sx/i, obj: { name:'frank', age: 18}, f1: (a, b) => a + b, f2: function(a, b) { return a + b } } const obj2 = deepClone(obj1) obj1.number = 2
解决环状问题
之前已经可以满足普通的深拷贝需要了,但此时还有个问题
那就是在深拷贝前,如果变量obj1的self等于自身,也就是说先做了obj1.self = obj1
的操作。
之后我们再运行const obj2 = deepClone(obj1)
这行代码,则会报错..
number :1, array : ( name : name : boot : false , str :' hi ',empty1: undefined ,empty2: null , JaCky ” date : new Date (2000,0,1,20,30,0), regex : /.( j | t ) sx /1,{ name :' frank ,, ( a , b )= t a + b function ( a , b ){ return a + b } age :18), undefined obj1.self=obj1 ¥{ number : I , bool : false , str :' hi ', emptyl : undefined ,empty2: null ,- > array :(2)[-),(-)] bool : false date : Sat Jan 01200020:30:00 GT +0800(中国标准时间))empty1: undefined empty2: null > fl :( a , b ) m > a + b >f2: f ( a , b ) number :1 obj :{ name :' frank ', age :18) rene A .( jlt ) sx / i self : array :(2)[(-),{)] bool :fal5e > date : Sat Jan 01200020:30:00 GT +e808(中国标准时间)() emptyl : undefined empty2: null >f1:( a , b )-> a + b >f2: f ( a , b ) number :1 > obj :{ name :' frank ', age :18) reoex :/.( j | t ) sx / i self : str :“ hi " >[ lPrototypel ]: Object : fnumber :1, bool : false , str :' hi ',empty1: undefined ,empty2: null ,-)
const obj1={ number :1, array : name : name : boot : false , str :' hi ',empty1: undefined ,empty2: nutl , frank , age : o jacky ', age : date : new Date (2000,0,1,20,30,0), 『巴 gex : 八.( jlt ) sx / i , obj : name :' Trank , age :18), 1: ( a , b )-- a + b , f2: function ( a , b ){ return a + b } < undefined objl . self =obj1 < fnumber :1, booi : false , str :' hi ', emptyl : undefined ,empty2: null ,-}> const obj2= deepClone (obj1) > Uncaught RangeError : Maximum call at deepClone (< anonymous >:1:21) deepClone (< anonymous >:29:23) deepClone (< anonymous >:29:23) deepClone (< anonymous >:29:23) deepClone (< anonymous >:29:23) deepClone (< anonymous >:29:23) deepClone (< anonymous >:29:23) deepClone (< anonymous >:29:23) deepClone (< anonymous >:29:23) deepC lone (< anonymous >:29:23) stack size exceeded
如何解决...
// 第一步 const cache = new Map() function deepClone(obj){ /* 其他代码 */ // 第二步 if(cache.get(obj)){ return cache.get(obj) } /* 其他代码 */ // 第三步 cache.set(a, result) for(let key in obj){ if(obj.hasOwnProperty(key)){ result[key] = deepClone(obj[key]) } } /* 其他代码 */ }
此时再运行obj1.self = obj1
+ const obj2 = deepClone(obj1)
,就不会再报错啦
const obj1= numoer :1 array :( name : name : bool : false , str :' hi ', emptyl : undefined ,empty2: nuti , frank , age : o : JaCKy , age : date : new Date (2000,0,1,20,30,0), regex ; .( jlt ) sx / i , ooJ :, f name :' frank ', age :18), ( a , b )=> a + b , 2 function ( a , b ){ return a + b } < undefined obj1.self=obj1 -> numDer :1,DO0l: : false , str :' hi ', emptyl : undefined ,empty2: null ,-} const obj2= deepClone (obj1)