3种深拷贝和4种浅拷贝的方法

浅拷贝

概念

自己创建一个新的对象,来接受你要重新复制或引用的对象值。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象;但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个对象改变了这个内存中的地址,肯定会影响到另一个对象。

1.Object.assign()

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

var obj = { name: "湖北彭于晏", age:22 };
var newobj = Object.assign({}, obj);
console.log(newobj); //{ name: "湖北彭于晏", age:22 }

assign()只能拷贝一层

2 ...展开运算符

  var obj = { name: "湖北彭于晏", age:22 };
    let newObj = {...obj};
    console.log(newObj);; //{ name: "湖北彭于晏", age:22 }

展开运算符和assign()方法基本一致,也只能拷贝一层

3.Array.prototype.concat

数组的 concat 方法其实也是浅拷贝,使用场景比较少,使用concat连接一个含有引用类型的数组时,需要注意修改原数组中的元素的属性,因为它会影响拷贝之后连接的数组

const arr = [1, 2, {name: 'nordon'}];
const newArr = arr.concat();
newArr[2].name = 'wy';
console.log(arr); 
console.log(newArr);

会发现arr和newArr索引2的数据都由 {name: 'nordon'} 变成了 {name: 'wy'}

4.Array.prototype.[slice]

数组的 slice 方法其实也是浅拷贝,使用场景比较少,同cancat

const arr = [1, 2, {name: 'nordon'}];
const newArr = arr.slice();
newArr[2].name = 'wy';

深拷贝

1. JSON.parse(JSON.stringify())

JSON.parse(JSON.stringify(obj)) 一般情况下对普通对象需要进行深拷贝,可以使用这种方法进行深拷贝操作,这种是最简单且代码量最少的深拷贝方法。

let a = { name: "湖北彭于晏", age:22}
let b = JSON.parse(JSON.stringify(a))
a.a = 11
console.log(a)//{ name: "湖北彭于晏", age:22}
console.log(b)//{ name: "湖北彭于晏", age:22}

不过好用归好用就是有缺陷

  • 1.如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象

  • 2.如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象

  • 3.如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失

  • 4.如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

  • 5.JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor

  • 6.如果对象中存在循环引用的情况也无法正确实现深拷贝

2. 递归深拷贝

<script>
        let obj = {
            name:'张三',
            age:20,
            hobby:['学习','上课','干饭'],
            student:{
                name:'尼古拉斯赵四',
                age:38
            }
        }

        //深拷贝函数
        function copy(obj,newObj){
            for(let key in obj ){
                if( obj[key] instanceof Array ){
                    newObj[key] = []
                    //递归调用 继续深拷贝数组
                    copy(obj[key],newObj[key])
                }else if( obj[key] instanceof Object ){
                    newObj[key] = {}
                    //递归调用 继续深拷贝对象
                    copy(obj[key],newObj[key])
                }else{
                    newObj[key] = obj[key]
                }
            }
        }

        //开始拷贝
        let newObj = {}
        copy(obj,newObj)

        newObj.name = '李四'
        newObj.hobby[0] = '游戏'
        newObj.student.name = '111'
        console.log(obj,newObj)
        
    </script>

除了麻烦基本没啥缺点

3. 装包

Lodash中的cloneDeep方法挺好用的

### `_.cloneDeep(value)`[​](https://www.lodashjs.com/docs/lodash.cloneDeep#_clonedeepvalue "标题的直接链接")

这个方法类似[`_.clone`](https://www.lodashjs.com/docs/lodash.cloneDeep#clone),除了它会递归拷贝 `value`。(注:也叫深拷贝)。

#### 添加版本

1.0.0

#### 参数

1.  `value`  *(*)* : 要深拷贝的值。

#### 返回

*(*)* : 返回拷贝后的值。

#### 例子

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects); console.log(deep[0] === objects[0]); // => false

 `_.cloneDeep(value)`

这个方法类似[`_.clone`],除了它会递归拷贝 `value`。(注:也叫深拷贝)。

#### 添加版本

1.0.0

#### 参数

1.  `value`  *(*)* : 要深拷贝的值。

#### 返回

*(*)* : 返回拷贝后的值。

#### 例子

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);// => false

lodash.cloneDeep | Lodash 中文文档 | Lodash 中文网 (lodashjs.com)