浅谈Javascript 浅拷贝和深拷贝的理解

   javascript中存储对象都是存地址的。

   浅拷贝:浅拷贝是都指向同一块内存区块,浅拷贝共用同一内存地址,你改值我也变。如果拷贝的对象里面的值是一个对象或者数组,它就是浅拷贝,拷贝的知识引用地址。 js的Object.assign,jquery的extend方法都是浅拷贝,一般的等号赋值也是浅拷贝 。

    

     上面vue里面的两个写法也是浅拷贝,具体地址为 https://cn.vuejs.org/v2/guide/list.html

   深拷贝:深拷贝则是另外开辟了一块区域,深拷贝是互不影响,你改值我也不变。angular里面的 angular.copy 是深拷贝。

   下面实例也可以看出这一点:

// 浅拷贝
const a = {t: 1, p: 'gg'};
const b = a;
b.t = 3;
console.log(a); // {t: 3, p: 'gg'}
console.log(b); // {t: 3, p: 'gg'}
//深拷贝
const c = {t: 1, p: 'gg'};
const d = deepCopy(c);
d.t = 3;
console.log(c); // {t: 1, p: 'gg'}
console.log(d); // {t: 3, p: 'gg'}
//浅拷贝  es6 扩展运算符
let a = [14,12,54,33,22];
let b = a;  // 相当于copy
a.push(44);
console.log(a); // [14, 12, 54, 33, 22, 44]
console.log(b); // [14, 12, 54, 33, 22, 44]

//深拷贝
let a = [14,12,54,33,22];
let b = [...a];
a.push(44);
console.log(a); // [14, 12, 54, 33, 22, 44]
console.log(b); // [14, 12, 54, 33, 22]

可以明显看出,浅拷贝在改变其中一个值时,会导致其他也一起改变,而深拷贝不会。

  Object.assign() ————深拷贝神器,这个方法就是用来拷贝一个对象的,通常做法就是Object.assign({}, sourceObject, { key1: value1,key2: value2})  {}表示目标对象,会定义成一个空的{},sourceObjec就是源对象
// Cloning an object
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
// Merging objects
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, target object itself is changed.
console.log(o2);//{b: 2} 源对象没有变
console.log(o3);// {c: 3}

是不是很完美,又可以clone又可以merge。在我这种情况下,我觉得我的代码量又可以减少了,比如:

const defaultOpt = {
    title: 'hello', 
    name: 'oo', 
    type: 'line'
};
// 原来可能需要这样
const opt1 = deepCopy(a);
opt1.title = 'opt1';
opt1.type = 'bar';
opt1.extra = 'extra'; // 额外增加配置
// 现在只要这样
const opt2 = Object.assign({}, a, {
    title: 'opt2', 
    type: 'bar', 
    extra: 'extra'
});
注:它只对顶层属性做了赋值,完全没有继续做递归之类的把所有下一层的属性做深拷贝。意思就是是拷贝一层,没有拷贝多层。
一层
{
   a: 1,
   b: 2,
}

多层
{
   a: 1,
   b: 2,
   c: {
      d: 4,
      e: {
          f: 6,
          g: 7
      }
   }
}

实现深拷贝,遍历key

function deepClone(obj){
    //判断obj是否为数组,如果是,初始化数组[],否则初始化对象{}
    let dcObj = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        //循环
        for(key in obj){
            //判断对象是否有key属性
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    dcObj[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    dcObj[key] = obj[key];
                }
            }
        }
    }
    return dcObj;
};
let t1 = {
    "a": 1,
    "b": 2,
    "c": {
        "d": 4,
        "e": {
            "f": 6,
            "g": 7
        }
    }
};
let t2=deepClone(t1);
t1.a=6;
console.log(t1);
/*
{
    "a": 6,
    "b": 2,
    "c": {
        "d": 4,
        "e": {
            "f": 6,
            "g": 7
        }
    }
}
*/
console.log(t2); //t1深拷贝给t2, b属性的值还是为2,没有改变,所以是深拷贝
/*
{
    "a": 1,
    "b": 2,
    "c": {
        "d": 4,
        "e": {
            "f": 6,
            "g": 7
        }
    }
}
*/

 参考:https://www.jianshu.com/p/a66050673663 


原文地址:https://www.cnblogs.com/allenhua/p/10863208.html