深拷贝和浅拷贝

30 阅读2分钟

一、简介

浅拷贝:不在堆内存中重新开辟空间,只复制栈内存中的引用地址,本质上两个对象(数组)依然指向同一块存储空间

深拷贝:在堆内存中重新开辟一个存储空间,完全克隆一个一模一样的对象;

二、深拷贝的三种实现方式

1、递归方式

手写实现深拷贝,使用递归实现原对象每一层的拷贝,当遇到基本数据类型时,直接拷贝,遇到引用数据类型时,递归拷贝它的每个属性。(最安全最常用)

function deepCopy(source,target){
    for(var key in source) {
        if(source.hasOwnProperty(key)){ // 只拷贝当前对象的属性
            // 判断是否为引用数据类型
            if(typeof source[key] == 'object'){
                // 引用数据类型,赋值为数组[]或者对象{},递归进行深拷贝。
                target[key] = Array.isArray(source[key])?[]:{};
                deepCopy(source[key],target[key]);
            } else {
                // 基本数据类型---浅拷贝
                target[key] = source[key];
            }
        }
    }
}

2、JSON.parse(JSON.stringify(obj))

缺点:

● 拷贝对象的值中如果有‘funciton’,‘undefined’,‘symbol’,在JSON.stringify()序列化后,键值对丢失

● 拷贝RegExp会变成空对象{}

● 对象中含有‘NaN’,‘Infinity’会变成null

● 拷贝Date会变成字符串

3、$.extend

jQuery中$.extend([deep],target,...object);

推荐在JQ中使用

4、lodash工具包

lodash中文文档

引入成功后,使用lodash提供的函数_.cloneDeep

三、浅拷贝

1、Object.assign

语法:.assign(target, ...sources)

target 目标对象,接收源对象属性的对象,也是修改后的返回值。 sources 源对象,包含将被合并的属性。(一维对象的深拷贝)

2、es6的扩展运算符

使用扩展运算符可以在构造字面量对象的时候,进行属性的拷贝。

语法:{...sources}

sources 源对象,包含将被合并的属性。

3、Array.prototype.concat()

语法:arr.concat(value0, /* … ,*/ valueN)

注:如果省略了所有 valueN 参数,则 concat 会返回调用此方法的现存数组的一个浅拷贝。

4、Array.prototype.slice()

语法:arr.slice(begin, end)

注:如果省略了 begin, end 参数,则 slice 会返回调用此方法的现存数组的一个浅拷贝。