浅拷贝跟深拷贝

90 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情

大家好,我是大帅子,今天给大家讲一下深浅拷贝,下面我们直接开始吧


浅拷贝

let obj = {
    name : "张三",
    age : 18
} 

目标: 把obj这个对象复制一份, 得到 obj1 ,保证 obj obj1 一模一样,但是又是完全独立的两个对象

做法: 就是把obj里面的属性全都拿出来 ,做循环,把属性赋值跟obj1,

示例代码 :

  1. 传统做法
function clone(obj) {
    let obj1 = {}
    for(let key in obj){
        obj1[key]=obj[key]
    }
}
  1. 我们es6出来的新语法有个扩展运算法 也就是所谓的 ...,解决了繁琐的代码
let obj = {name : 'zs',age:18}
obj1 = {...obj}

image.png

这里我们实现的就是浅拷贝哦

深拷贝 (deep clone) 在浅拷贝的基础上,对当前要复制的内容进行判断:如果仍是一个对象,则再次调用拷贝函数。

var obj = { name: '小王', hobby:['reading','running'] }

// 对于当前要拷贝的内容,如果还是一个对象,则要递归调用,而不是直接赋值

function deepCopy(obj){
   // 定义一个空的对象或者是数组
   // 如果当前要复制的是数组就用一个空数组,或者用一个空对象。
   // var tempObj =  Array.isArray(obj) ? [] : {}
   var tempObj = {}
   if(  Array.isArray(obj) ) {
       tempObj = []
   }

   // var tempObj =  {}
   // .... 操作
   for(var key in obj) {
       var t = obj[key]
       // 当要拷贝的内容还是一个对象或者是数组
       if(Array.isArray(t) || typeof t === "object") {
           tempObj[key] = deepCopy(obj[key])
       }
       else // 当要拷贝的内容只是一个基本类型的数据
       {
           tempObj[key] = t
       }
   }
   return tempObj
}

var obj1 = deepCopy(obj);
// 验证:
// 给 obj1.hobby.添一个信息,不会影响obj.hobby. 
obj1.hobby === obj.hobby; // false

上面的代码可以简化如下:

 function isObj(obj) {
     return (typeof obj === 'object' || typeof obj === 'function') && obj !== null
    }
    function deepCopy(obj) {
        var tempObj = Array.isArray(obj) ? [] : {}
        for(var key in obj) {
            tempObj[key] = isObj(obj[key]) ? deepCopy(obj[key]) : obj[key]
        }
        return tempObj
    }

上面的代码在没有遇到循环引用之前都是正常工作的。下面将来介绍循环引用 。

循环引用 下面来看一个循环引用的例子:

注意下面第5行代码,obj.a还是指向了obj,这里就构成了一个环。

var obj = {
    name: '小王',
    hobby: ['reading', 'running'],
}
obj.a = obj; // 手动加上循环引用
function isObj(obj) {
    return (typeof obj === 'object' || typeof obj === 'function') && obj !== null
 }
 function deepCopy(obj) {
     var tempObj = Array.isArray(obj) ? [] : {}
     for (var key in obj) {
         tempObj[key] = isObj(obj[key]) ? deepCopy(obj[key]) : obj[key]
     }
     return tempObj
 }
 
 var obj1 = deepCopy(obj)
 console.log(obj);
 console.log(obj1);
 
console.log(obj1.hobby === obj.hobby);

导致的后果就是

image.png

Object.assign()拷贝

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

通过jQuery的extend方法实现深拷贝

let $ = require('jquery');
let obj1 = {
   a: 1,
   b: {
     f: {
       g: 1
     }
   },
   c: [1, 2, 3]
};
let obj2 = $.extend(true, {}, obj1);

lodash.cloneDeep()实现深拷贝

let _ = require('lodash');
let obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
let obj2 = _.cloneDeep(obj1);

使用递归的方式实现深拷贝

function _deepClone(source) {
  let target;
  if (typeof source === 'object') {
    target = Array.isArray(source) ? [] : {}
    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        if (typeof source[key] !== 'object') {
          target[key] = source[key]
        } else {
          target[key] = _deepClone(source[key])
        }
      }
    }
  } else {
    target = source
  }
  return target
}

JSON.stringify 和 JSON.parse

用 JSON.stringify 把对象转换成字符串,再用 JSON.parse 把字符串转换成新的对象。

可以转成 JSON 格式的对象才能使用这种方法,如果对象中包含 function 或 RegExp 这些就不能用这种方法了。

//通过js的内置对象JSON来进行数组对象的深拷贝
function deepClone(obj) {
  let _obj = JSON.stringify(obj);
  let objClone = JSON.parse(_obj);
  return objClone;
}

好了,这边已经给大家介绍到这里,以上是我自己的理解,希望可以帮到大家, 欢迎留言我这边一定会第一时间给大家解答,喜欢的可以点赞收藏,
🐣---->🦅        还需努力!大家一起进步!!!