js浅拷贝和深拷贝

vue开发过程中,由于常常与数据打交道,弄懂每个data的状态是很有必要的。如果数据耦合度较高,弄懂浅拷贝和深拷贝就显得尤为重要。因此在此总结一下。

1.对于基本数据类型,由于变量名和值都存在栈内存中,因此,简单的=会开辟一个新空间,赋值和被复制的变量都是相互独立的:

let a = "aaa";
let b;
b = a;
b = "bbb";
// 这里输出bbb
console.log(b);

结果如下:

 

 

 2.接下来我们讨论较为复杂的object类型的数据。由于引用数据类型名字存在栈内存中,值存在堆内存中,栈内存会提供一个引用的地址指向堆内存中的值。当我们用=进行赋值时,其实只是复制了引用地址,如果这时改变值,会影响到赋值与被复制的双方:

 

浅拷贝可以用=赋值或者 Object.assign方法,这里重点说下深拷贝方法

深拷贝实现方法:

(1)for···in     循环到第一层:

var obj1 = {
  a: "aaa",
  b: "bbb",
  c: {
    d: "ddd",
  },
};
obj2 = {};
for (let i in obj1) {
  obj2[i] = obj1[i];
}
obj2.a = "aaa2";
obj2.c.d = "ddd2";
console.log(obj1);
console.log(obj2);

结果如下:

 

 发现只有a改变了,c并没有改变,不算是真正的深拷贝,但我们这里有个思路:递归实现不就行了

function deepClone(obj){
    // 考虑到objClone变量的多样性
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断obj子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a={
    a: "aaa",
    b: "bbb",
    c: {
      d: "ddd",
    },
  };
b=deepClone(a);
a.a="aaa2";
a.c.d="ddd2"
console.log(a);
console.log(b);

结果如下:

 

 发现不论多少层都能实现a和b互不干扰。

(2)此外,我们还可以通过loadash库实现深拷贝:

let result = _.cloneDeep(test)

(3)通过JSON对象来实现深拷贝,这个方法比较取巧,且不依赖其他库,在我编程中用的最多:

function deepClone(obj) {
  var temp_obj = JSON.stringify(obj),
    objClone = JSON.parse(temp_obj);
  return objClone;
}

对于数组,我们可以用slice和concat实现数组的深拷贝:

// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
// 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
var arr1 = ["1","2","3"]; 
var arr2 = arr1.slice(0);
arr2[1] = "9";
console.log("数组的原始值:" + arr1 );
console.log("数组的新值:" + arr2 );
// 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "9";
console.log("数组的原始值:" + arr1 );
console.log("数组的新值:" + arr2 );
// 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
var arr1 = [{a:1},{b:2},{c:3}];
var arr2 = arr1.concat();
arr2[0].a = "9";
console.log("数组的原始值:" + arr1[0].a ); // 数组的原始值:9
console.log("数组的新值:" + arr2[0].a ); // 数组的新值:9

以上就是常用的拷贝技巧,希望对大家有所帮助。

posted @ 2020-08-09 12:14  Do丶  阅读(169)  评论(0编辑  收藏  举报