关于深拷贝和浅拷贝

从原理看:

  • 浅拷贝:拷贝一层,对象级别的则拷贝引用
  • 深拷贝:拷贝多层,每个层级的属性都会拷贝

从现象看:
A复制了B,B被修改后,

  • A随B变化而变化->浅拷贝
  • A不变->深拷贝

深拷贝针对的s复杂的object类型数据
∴如直接赋值的单层拷贝,如b=a,b虽然不受a的影响,但是这也不算做深拷贝
现象只是作为方便理解的一个参考,真正的判断标准还是要从原理上看


数据类型分为:

  1. 基本数据类型(7种):namevalue都存储在栈内存中
  2. 引用数据类型:name->栈内存,值->堆内存,栈内存会提供一个引用的地址指向堆内存的值

clipboard.png

当b=a进行拷贝时,b复制的是a的引用地址,并不是堆里面的值,所以这便造成了当a发生改变,b也会随之改变的浅拷贝


实现浅拷贝的方法:
一、 直接复制

//基本数据类型
var arr = [1, 2, 3, '4'];

var arr2 = arr;
arr2[1] = "test"; 
console.log(arr); // [1, "test", 3, "4"]
console.log(arr2); // [1, "test", 3, "4"]
//改变其中一个对象的属性值,两个对象都发生了改变 
//obj和obj2两个变量都指向同一个指针,赋值时只是复制了指针地址,它们指向同一个引用,∴当我们改变其中一个的值,另一个变量的值也会随之改变


----------


//对象级
function Clone(obj1){
    var obj2 ={};
    for(var i in obj1)
    {
        obj2[i]=obj1[i];
    }
    return obj2;
}

浅拷贝只是拷贝了一层,除了对象是拷贝引用类型,其他的都是直接将值传递,有自己的内存空间

二、ES6中的Object.assign()方法
该方法可以把任意多个的源对象自身的可枚举属性拷贝给对象,然后返回目标对象

Object.assign(目标对象,任意多个源对象)
var obj1 = {
    a: "hello",
    b: {
        a: "hello",
        b: 21}
};
 
var cloneObj1= Object.assign({}, obj1);
cloneObj1.a = "changed";
cloneObj1.b.a = "changed";
console.log(obj1.a);  //hello
console.log(obj.b.a); // "changed"

如果对象只有一层,这个函数可以作为深拷贝的方法

var obj2 = { a: 10, b: 20, c: 30 };
var cloneObj2 = Object.assign({}, obj2);
cloneObj2.b = 100;
console.log(obj2);
// { a: 10, b: 20, c: 30 } <-- 没有改变,实现了深拷贝
console.log(cloneObj2);
// { a: 10, b: 100, c: 30 }

若想实现深拷贝,就需要在堆中开辟一个内存,用来存放b的值。

方法一、手动复制
将A对象项的属性逐个负责给另一个对象的属性

var ob1 = {a:1,b:2,c:3};
var ob2 = {a:ob1.a,b:ob1.b,c:ob1.c};
ob1.a = 0;
ob2.b = 0;
console.log(ob1);//023
console.log(ob2);//103

这样很麻烦,且本质上不能算作深拷贝,当ob1内嵌套对象c时,ob1和ob2将共享c,当改变c的属性时,ob1ob2将都发生改变

方法二、将对象通过JSON方法转成字符串再转回来
可以实现真正的深拷贝,但是只能用于可以转成JSON格式的对象,function无法转换成JSON,就不能够使用
∴此方法会舍弃对象的构造函数

var ob1 ={c:{a:1,b:2}};
var ob2 =JSON.parse(JSON.stringfy(ob1));
//用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象

方法三、递归拷贝

function deepClone(obj1,obj2){
    var obj = obj2|| {};//如果obj存在则定义为obj2,否则建立空对象
        for(var i in obj1){//遍历原对象
        if(typeof obj1[i] === 'object'){//如果当前元素是对象
        
            obj[i] = Array.isArray(obj1[i]) ?[]:{};//判断是数组还是对象 
            deepClone(obj1[i],obj[i]);//利用递归逐层遍历直到最后一层
        }
        else{

            obj[i] = obj1[i];//赋值
        }
        
    }
    return obj;

}

var str = {};
var obj = { a: {a: "Leemo", b: 19980228} };
deepClone(obj, str);
console.log(str.a);

方法四、使用Object.create()方法

var Obj2 = object.create(Obj1);
//实现Obj2深拷贝Obj1

参考文档:
文档1
文档2


李默
24 声望2 粉丝