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

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

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


目录
相关文章
|
7月前
|
C语言
C 语言中布尔值的用法和案例解析
在编程中,您经常需要一种只能有两个值的数据类型,例如: - 是/否 - 开/关 - 真/假 为此,C语言有一个 `bool` 数据类型,称为布尔值。
234 1
|
6月前
|
存储 C# 开发者
C# 编程基础:注释、变量、常量、数据类型和自定义类型
C# 编程基础:注释、变量、常量、数据类型和自定义类型
|
7月前
|
关系型数据库 MySQL Linux
【MySQL-10】数据库函数-案例演示【字符串/数值/日期/流程控制函数】(代码演示&可cv代码)
【MySQL-10】数据库函数-案例演示【字符串/数值/日期/流程控制函数】(代码演示&可cv代码)
【MySQL-10】数据库函数-案例演示【字符串/数值/日期/流程控制函数】(代码演示&可cv代码)
|
7月前
02-python的基础语法-标识符/运算符/字符串拓展/字符串的拼接/字符串格式化/字符串精度控制/字符串格式化方式2/对表达式进行格式化/练习题/数据输入-input语句
02-python的基础语法-标识符/运算符/字符串拓展/字符串的拼接/字符串格式化/字符串精度控制/字符串格式化方式2/对表达式进行格式化/练习题/数据输入-input语句
|
C语言
学C的第二天(变量‘补充’;简单了解常量,字符串,转义字符,注释,if选择语句,while循环语句)(1)
4.4*变量的使用(上期继续补充): 字符类型: %c - 字符类型 %d - 整型 %s - 字符串 %f - float类型 %lf - double类型
112 0
|
Python
Python函数详解:参数、返回值和文档字符串
Python函数详解:参数、返回值和文档字符串
170 0
LeetcodeSQL入门——知识点总结(选择/排序/修改/字符串处理/正则)
LeetcodeSQL入门——知识点总结(选择/排序/修改/字符串处理/正则)
|
存储 程序员 C语言
(第16列)C语言:计算输入的一行字符串中有多少个单词。顺便补充“gets函数”的用法。
(第16列)C语言:计算输入的一行字符串中有多少个单词。顺便补充“gets函数”的用法。
(第16列)C语言:计算输入的一行字符串中有多少个单词。顺便补充“gets函数”的用法。
|
Python
Python 技巧篇-字符串灵活处理:字符串过滤、字符串拼接,字符串切片,特殊、超长字符串的处理实例演示
Python 技巧篇-字符串灵活处理:字符串过滤、字符串拼接,字符串切片,特殊、超长字符串的处理实例演示
197 0
Python 技巧篇-字符串灵活处理:字符串过滤、字符串拼接,字符串切片,特殊、超长字符串的处理实例演示
下一篇
DataWorks