js如何实现深度克隆,带你理解掌握浅拷贝和深拷贝......

1.首先我们先来理解一下什么是浅拷贝,什么是深拷贝吧

浅拷贝(对象/数组) 特点:
  -  拷贝的是引用(即地址值),修改拷贝以后的数据,会影响原数据
  -  拷贝数据的方法(浅拷贝)
      1. 直接赋值给一个变量   //浅拷贝
      2. Object.assign()    //浅拷贝
      3. Array.prototype.concat()  //浅拷贝
      4. Array.prototype.slice()   //浅拷贝
  -  下面我们用代码来辅助理解
//  1. 直接赋值给一个变量   //浅拷贝
         let obj1 = {name:'coderlyk',age:31}
         let obj2 = obj1
         
         obj2.name = "newname"//obj1和obj2的name属性值都改变了,浅拷贝
         console.log(obj1,obj2)//两个对象都返回{name:'newname',age:31}
//  2. Object.assign()     //浅拷贝
          let obj1 = {name:'kobe',age:29}
          let obj2 = Object.assign(obj11)
          
          obj2.name = "wade"//obj1和obj2的name属性值都改变了,浅拷贝
          console.log(obj1,obj2)//两个对象都返回 {name:'wade',age:29}
//  3. Array.prototype.concat()  //浅拷贝
          let arr1 = [1,2,true,{name:'TT',age:26}]
          let testArr = [3,4]
          let arr2 = arr1.concat(testArr)
          
          console.log(arr2)
          arr2[1] = "a"//只改变了arr2
          arr2[3].name="james"//arr1[3]和arr2[3]的name属性值都改变了,浅拷贝
          console.log(arr1,arr2)
//  4. Array.prototype.slice()  //浅拷贝
          let arr1 = [3,8,false,{name:'冷嘉琪',age:18}]
          let arr2 = arr2.slice()
          
          arr2[3].name = '大帅哥'//arr1[3]和arr2[3]的name属性值都改变了,浅拷贝
          console.log(arr1,arr2)


深拷贝(深度克隆)特点:
  -  拷贝后,生成一块新的内存来存放拷贝的数据,修改拷贝以后的数据,不会影响原数据
  -   拷贝数据的方法(深拷贝)
       1.JSON.parse(JSON.stringify(arr/obj))  //深拷贝(深度克隆),
          注意:拷贝的数据里不能有函数,不能处理
  -  下面我们用代码来辅助理解
//  5. JSON.parse(JSON.stringify(arr/obj)),深拷贝(深度克隆),拷贝的数据里不能有函数,处理不了
         let arr1 = [3,8,false,{name:'oldname',age:20},function fun(){console.log('fun')}]
         let arr2 = JSON.parse(JSON.stringify(arr1))
         //先通过JSON.stringify方法将arr1变成JSON字符串,再通过方法JSON.parse将JSON字符串转成数组,从而实现拷贝
         
         arr2[3].name = 'newname'//arr2[3]的name属性值改变了,arr1[3]的name属性值没变,深拷贝
         console.log(arr1)//(5) [3, 8, false, {…}, ƒ] 
         console.log(arr2)//(5) [3, 8, false, {…}, null]  //函数拷贝过来变成了null  

2.如何实现深度克隆

2.1 了解如何判断数据类型,并将判断之后的数据类型的相应字符串提取出来,方便我们实现深度克隆时进行判断

/* 如何判断数据类型: arr ----> Array    null---->Null
    1. typeof 返回的数据类型:String,Number,Boolean,Undefined,Object,Function,NUll...
    2. Object.prototype.toString.call(obj)  用它判断数据类型的返回值是:[Object 数据类型] -》我们需要把这个数据类型字符串提取出来
*/  
   let n = null
   console.log(typeof n)//object

   let result = Symbol('lyk')
   console.log(Object.prototype.toString.call(result))// [object Symbol]
   console.log(typeof Object.prototype.toString.call(result))//string   -》说明返回的[object Symbol] 是一个字符串
   //提取判断后数据类型字符串
   console.log(Object.prototype.toString.call(result).slice(8,-1))//Symbol

2.2 将我们深度克隆的全部代码逻辑奉上

// 1. 定义检查数据类型的功能函数
    function checkedType(target){
        return Object.prototype.toString.call(target).slice(8,-1)//如 [Object Array]  我们这样截取的就是Array
    }
// 2.实现深度克隆 --->  对象/数组  
    function clone(target){
        // 判断拷贝的数据类型
        // 初始化变量result  成为最终克隆的数据
       
        let result, targetType = checkedType(target)

        if(targetType === 'Object'){
            result = {}
        }else if (targetType === 'Array') {
            result = []
        }else{
            return target
        }

    // 遍历目标数据
      for(let i in target){
        //   获取遍历数据的每一项值
        let value = target[i]
        // 判断目标结构里的每一个值是否存在对象/数组
        if(checkedType(value) === 'Object' || checkedType(value) === 'Array'){// 对象/ 数组里嵌套了对象/数组
             //继续遍历获取到的value值
               result[i] = clone(value)//递归
           }else {//获取到的value值是基本的数据类型或者是函数
               result[i] = value
           }
      }
      return result;
    }
    let fun = function(){
        console.log('我是fun函数')
    }
    let setArr = [1,5,true,{name:'boss',age:40},fun]
    let setNew = clone(setArr)
       setNew[3].name = "大boss"
       console.log(setArr,setNew)
       setNew[4]()

猜你喜欢

转载自blog.csdn.net/qq_43528628/article/details/106299563