JS中的深拷贝与浅拷贝

135 阅读2分钟

JS中的深拷贝与浅拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

浅拷贝

(1) 直接赋值

//同一个地址
 var arr = { } 
 arr2 = arr 

(2) Object.assign() 只是一级属性复制,比浅拷贝多拷贝一层。

 const target = { a: 1, b: 2 };
 const source = { b: 4, c: 5 };
 
 const returnedTarget = Object.assign(target, source);
 
 console.log(target);
 //{ a: 1, b: 4, c: 5 }
 
 console.log(returnedTarget);
 //{ a: 1, b: 4, c: 5 

(3) 展开运算符...,只是一级属性复制,比浅拷贝多拷贝一层

 let obj={
     name:"jack",//不受影响
     arr:[1,2,3] //拷贝地址,还是同一个值
 }
 let new={...obj}
 new.arr.splice(1,1)
 //obj arr:[1,3]
 //new arr:[1,3]

深拷贝

(1) JSON.parse(JSON.stringify())数组对象都好用的方法

缺点: 不能有undefinedfunction

 const obj1 = JSON.parse(JSON.stringify(obj));
 //undefind与function直接丢失

(2) 递归深复制,一层层复制,性能不好,占用内存

 function deepCopy(newData,oldData) {
     for (let key in oldData) {
                   //判断属性值属于哪种数据类型 根据属性值类型的不同做不同的操作
                   //1.获取属性值 oldobj[Key]
                   let item = oldData[key]
                   //2.1判断这个值是否是数组
                   //2.2判断这个值是否是对象
                   //2.3否则属于简单数据类型
                   if (item instanceof Array) {
                     newData[key] = []
                     deepCopy(newData[key], item)
                   } else if (item instanceof Object) {
                     newData[key] = {}
                     deepCopy(newData[key], item)
                   } else {
                     newData[key] = item
                   }
      }
 }
 
 
  const cloneDeep = data => {
     const newData = Array.isArray(data) ? [] : {}
     for (let key in data) {
         if (data[key] && typeof data[key] === 'object') {
             newData[key] = cloneDeep(data[key])
         } else {
             newData[key] = data[key]
         }
     }
     return newData
 }
 

(3)优化方案

 /**
  * 判断对象属性值是否有对象
  * @param {} data
  * @returns
  */
 const isObjectValue = data => {
     for (let key in data) {
         if (data[key] && typeof data[key] === 'object') {
             if(Object.prototype.toString.call(data[key]) !== '[object Function]'){
                 return true
             }
         }
     }
 }
 
 /**
  * 递归判断数据类型
  *   Function或undefined返回为true
  */
 const isFunctionOrUndefined = data => {
     for (let key in data) {
         if (data[key] === undefined) {
             return true
         } else if (data[key] && Object.prototype.toString.call(data[key]) === '[object Function]') {
             return true //Function
         } else if (data[key] && typeof data[key] === 'object') {
             isFunctionOrUndefined(data[key])
         }
     }
 }
 
 /**
  * 拷贝对象 优化方案
  * @param {*} obj 原对象
  * @param {*} cloneObj 返回拷贝对象
  */
 const cloneDeepObj = obj => {
     if (obj === undefined) {
         throw new TypeError('param is not undefined')
     }
     //判断拷贝对象只有一层及属性值都不是对象,使用Object.assign()
     if (!isObjectValue(obj)) {
         return  { ...obj }
     }
     //判断类型,如果不是Function或undefined使用JSON方式
     if (!isFunctionOrUndefined(obj)) {
         return JSON.parse(JSON.stringify(obj))
     }
  
     return cloneDeep(obj)
 
 }
 

思考:

数组中的map方法是深拷贝还是浅拷贝呢?

 let arr = [1, 2, { name: "jack" }, [5, 6, 7]]
 let newarr = arr.map((item) => item)
 arr[2].name = 'root'
 arr[0] = 0
 
 console.log("旧数组>>>", arr);
 //0: 0
 //1: 2
 //2: {name: 'root'}
 //3: (3) [5, 6, 7]
 console.log("新数组---", newarr);
 //0: 1
 //1: 2
 //2: {name: 'root'}
 //3: (3) [5, 6, 7]
 
 
 //结果:只是一级属性复制,比浅拷贝多拷贝了一层