手写支持函数、日期和正则的深拷贝

简介: 手写支持函数、日期和正则的深拷贝

使用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)


目录
相关文章
|
1月前
|
JavaScript 前端开发
模板字符串中怎样使用字符串模板字面量?
通过以上这些方式,可以充分发挥模板字符串和字符串模板字面量的强大功能,更灵活、高效地处理字符串操作,提高代码的可读性和可维护性。
24 2
ES6学习(3)模板字符串、简化对象和函数写法
ES6学习(3)模板字符串、简化对象和函数写法
|
6月前
|
人工智能 Java 数据格式
JavaSE——正则表达式(1/2):概述、初步使用(普通方法,正则表达式)、书写规则(字符类,预定义字符,数量词,其他,特殊案例)
JavaSE——正则表达式(1/2):概述、初步使用(普通方法,正则表达式)、书写规则(字符类,预定义字符,数量词,其他,特殊案例)
53 3
|
编译器 C++ Kotlin
【Kotlin】基础速览(1):操作符 | 内建类型 | 类型转换 | 字符串模板 | 可变 var 和不可变 val
【Kotlin】基础速览(1):操作符 | 内建类型 | 类型转换 | 字符串模板 | 可变 var 和不可变 val
77 0
|
7月前
02-python的基础语法-标识符/运算符/字符串拓展/字符串的拼接/字符串格式化/字符串精度控制/字符串格式化方式2/对表达式进行格式化/练习题/数据输入-input语句
02-python的基础语法-标识符/运算符/字符串拓展/字符串的拼接/字符串格式化/字符串精度控制/字符串格式化方式2/对表达式进行格式化/练习题/数据输入-input语句
|
7月前
|
JavaScript 前端开发 Java
字符串的引用方式
字符串的引用方式
162 0
|
开发框架 数据库
GoFrame代码优化:使用gconv类型转换 避免重复定义map
最近一直在研究 GoFrame 框架,经过一段时间的使用、总结、思考,发现确实不失为一款非常值得使用的企业级开发框架。
442 0
|
Java Linux 开发工具
JavaSE (二)原生数据类型(变量与变量的定义、注释)等说明
JavaSE 原生数据类型(变量与变量的定义、注释)等说明
102 0
python_正则表达式中在模板字符串前加r怎么理解
python_正则表达式中在模板字符串前加r怎么理解
581 0
python_正则表达式中在模板字符串前加r怎么理解
|
安全 Java 编译器
语法糖甜不甜?巧用枚举实现“状态”转换限制
语法糖甜不甜?巧用枚举实现“状态”转换限制
198 0