手写深浅拷贝|八月更文挑战

287 阅读4分钟

这是我参与8月更文挑战的第1天,活动详情查看: 8月更文挑战

实现浅拷贝

首先浅拷贝是指,一个新的对象对原始对象的属性值进行精确的拷贝,如果拷贝的是基本数据类型,拷贝的就是基本数值类型的值,如果是引用数据类型,拷贝的就是地址指针。如果其中一个对象的引用内存地址发生改变,另一个对象也会发生改变。

Object.assign() :

接收的第一个参数是目标对象,其余参数是源对象

用法:Object.assign(target,source_1,...),该方法可以实现浅拷贝,也可以实现一维数组的深拷贝。

注意:

  • 如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性
  • 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回
  • 因为null和undefined不能转为对象,所以第一个参数不能为null或者undefined
 let target = {a: 1};
 let object2 = {b: 2};
 let object3 = {c: 3};
 Object.assign(target,object2,object3);  
 console.log(target);  // {a: 1, b: 2, c: 3}

扩展运算符

可以使用扩展运算符进行属性的拷贝。

 let obj1 = {a:1,b:{c:1}}
 let obj2 = {...obj1};
 obj1.a = 2;
 console.log(obj1); //{a:2,b:{c:1}}
 console.log(obj2); //{a:1,b:{c:1}}
 obj1.b.c = 2;
 console.log(obj1); //{a:2,b:{c:2}}
 console.log(obj2); //{a:1,b:{c:2}}

数组方法实现浅拷贝

Array.prototype.slice()

这是JavaScript数组的一个方法,这个方法可以从已有的数组中返回选定的元素,用法:

array.slice(start,end),该方法不会改变原数组,并且返回一个新数组

该方法如果不带参数则可以实现一个对数组的拷贝。

 let arr = [1,2,3,4];
 console.log(arr.slice()==arr.slice())//false
 console.log(arr==arr.slice())//false

Array.prototype.concat()

concat()方法用于合并两个或者多个数组。此方法不会更改原数组,而是返回一个新数组。

该函数有两个参数,两个参数都可选,如果不写则可以实现数组的浅拷贝

手动实现浅拷贝

  function shollowCopy(object) {
     // 判空与类型处理
     if (!object || typeof object != "object") return
     let tar = Array.isArray(object) ? [] : {}
     for (const key in object) {
       if (object.hasOwnProperty(key)) {
         tar[key] = object[key]
       }
     }
     return tar
   }
 ​
   //测试
   let arr = [12, 54, 567, 87, 9]
   let test = shollowCopy(arr)
   console.log(test)
   console.log(test === arr)

实现深拷贝

浅拷贝:浅拷贝指的是将一个对象的属性值复制到另一个对象,如果值有引用类型的话,那么会将这个引用的地址复制给对对象,因此两个对象会有同一个引用类型的引用。浅拷贝可以使用Object.assign和展开运算符来实现,数组可以使用slice、concat来实现

深拷贝:深拷贝相对于浅拷贝而言,如果遇到属性值为引用类型的时候,他将新建一个引用类型并将对应的值复制给它,因此对象获得的一个新的引用类型而不是一个原有类型的引用。深拷贝对于一些对象可以使用JSON的两个函数来实现,但是由于JSON的对象格式比js的对象格式更加严格,所以如果属性值里面出现函数或者Symbol类型的值时会转换失败

JSON.stringify()

  • json.parse(JSON.stringify(obj))时目前比较常用的深拷贝方法之一,它的原理就是利用JSON.stringify将js对象序列化,在使用JSON.parse反序列化(还原)js对象
  • 这个方法可以简单粗暴的实现深拷贝,但是还是存在问题,拷贝的对象中如果有函数、undefined、symbol,当使用过JSON.stringify进行处理后,都会消失。
  let obj = {
     a: 0,
     b: {
       c: 0
     } 
   }
   let obj2=JSON.parse(JSON.stringify(obj))
   console.log(obj2)
   console.log(obj.b===obj2.b)//false

手写深拷贝

实际上就是在我们浅拷贝的基础上做了一层递归,如果我们正在赋值的对象时一个object类型的话,我们直接将其再次浅拷贝里面的值返回给当前的值,这样就不会出现拷贝以后发现引用类型的值依然指向同一块内存空间的问题。

   function deepCopy(obj) {
     if (!obj || typeof obj !== "object") return
     let newobj = Array.isArray(obj) ? [] : {};
     for (const key in obj) {
       if (obj.hasOwnProperty(key)) {
         newobj[key] = typeof obj[key]==="object"?deepCopy(obj[key]):obj[key]
       }
     }
     return newobj
   }
 //测试
  let tt=deepCopy(obj)
   tt.b.c=111111
   console.log(tt)
   console.log(obj)

\