JS深拷贝和浅拷贝

时间:2021-08-08 21:59:52

JS中对象分为基本类型和复合(引用)类型,基本类型存放在栈内存,复合(引用)类型存放在堆内存中
堆内存中用于存放由new创建的对象,栈内存存放一些基本类型的变量和对象的引用变量

对于简单变量,内存小,直接复制不会发生引用:

var a = 123;
var b = a;
a = 123456;
console.log(a);//123456
console.log(b);//123

var a = 'abc'var b = a;
a = 'abcde';
console.log(a);//abcde
console.log(b);//abc

而对于对象的这种内存占用的比较大的来说,直接让复制的东西等于要复制,就会发生引用,因为这种复制将复制的东西指向了要复制的东西,简单的说,就是两个都指向了同一个空间,如果改变其中一个,另一个也会发生变化。

引用只发生在对象身上
var arr1 = [1,2,3];
var arr2 = arr2;
arr1.push(4);
console.log(arr1);//1234
console.log(arr2);//1234
arr2.push(5);
console.log(arr1);//12345
condole.log(arr2);//12345
ES6新方法用于复制数组,避免发生引用的方法

方法一:Array.from(要复制的数组)

var arr1 = [1,2,3];
var arr2 = Array.from(arr1);
arr.push(4);
console.log(arr1);//1234
console.log(arr2);//123
arr2.push(5);
console.log(arr1);
console.log(arr2);//1235

方法2: …

var arr1 = [1,2,3];
var arr2 = [..arr1];
arr1.push(4);
console.log(arr1);//1234
console.log(arr2);//123
arr2.push(5);
console.log(arr1);//1234
console.log(arr2);//1235

第二种方法也可以用在函数的行参上面

function show(...ar1){//直接复制arguments这个伪数组,让它变成真正的数组,从而拥有数组的方法
console.log(arr1);
arr1.push(5);
console.log(arr1);//12345
}
show(1,2,3,4);

或者通过循环来复制:

var arr1 = [1,2,3,4];
var arr2 = [];
for(var i = 0;i<arr1.length;i++){
  arr2[i] = arr1[i];
}
arr1.push(5);
arr2.push(6);
console.log(arr1);//12345
console.log(arr2);//12346

//或者是json
var json = {"name":"xuaohu",age":"12","job":"学生"}; var json2 = {}; for(var name in json1){ json2[name] = json1[name]; } console.log(JSON.stringfy(json1));//{"name":"xioahu","age":12,"job":"学生"}; console.log(JSON.stringfy(json2));//{"name":"xiaohu","age":12,"job":"学生"} json1.a = 1; json2.b = 2; console.log(JSON.stringfy(json1));//{"name":"xiaohu","age":12,"job":"学生","a":1} console.log(JSON.stringfy(json2));//{"name":"xiaohu","age":12,"job","b":2} 

深复制和浅复制最根本的区别在是否真正获取了一个对象的实体而不是引用
1.深复制在计算机中开辟了一块内存地址用于存放复制的对象
2.浅复制仅仅指向被复制的内存地址,如果原地址对象被改变了,那么浅复制出来的对象也会对象相应的改变。

所谓的浅复制,只是拷贝了基本类型数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅复制(浅拷贝)

var json1 = {"a":"xiaohu","arr1":[1,2,3]}
function copy(obj1) {
    var obj2 = {};
    for (var i in obj1) {
      obj2[i] = obj1[i];
    }
    return obj2;
}
var json2 = copy(json1);
json1.arr1.push(4);
alert(json1.arr1);  //1234
alert(json2.arr1)  //1234

而深复制的话,我们要求复制一个复杂的对象,那么我们就可以利用递归的思想来做,考虑提升性能又不会发生引用

var json1 = {"name":"xiaohu","age":20,"arr1":[1,2,3,4,5],"string":'abcd',"arr2":[1,2,3,4,5,6],"arr3":[{"name":"xioahu"},{"job":'student'}]}
var json2 = {};
//最初的时候给他一个初始值或者他自己本身就是一个json
  var obj2 = obj2||{};
  for(var name on obj1){
    if(typeof obj1[name] === 'object'){//先判断obj[name]是不是一个对象
     obj2[name] = (obj1[name].constructor===Array)?[]:{};
     copy(obj1[name],obj2[name]);
  }else{
  //如果不是对象,直接等于就可以,不会发生引用
     obj2[name] = obj1[name];
  }
}
return obj2; 
}
json2 = copy(json1,json2);
json1.arr1.push(6);
console.log(json1.arr1);//123456
console.log(jaon2.arr1);//12345