浅拷贝与深拷贝
浅拷贝和深拷贝是针对引用数据类型(对象、数组)而言的。以对象为例,下面一段代码是将对象obj1
赋值给变量obj2
:
const obj1 = { a: 1, b: 2, c: 3, };
const obj2 = obj1;
console.log(obj2); // {a: 1, b: 2, c: 3}
值得注意的是,上面将对象obj1
赋值给一个变量obj2
时,并不是给该变量重新生成一个相同的对象,而是将该对象的索引指向该变量,也就是说obj1
和obj2
指向同一个对象,它们本质上是同一个对象,可通过改变obj1
或obj2
的值来证明。当改变obj2
中的值时,相应的obj1
对应的值也发生变化。
const obj1 = { a: 1, b: 2, c: 3, };
const obj2 = obj1;
obj2.a = 'change'
console.log(obj1); // {a: "change", b: 2, c: 3}
console.log(obj2); // {a: "change", b: 2, c: 3}
上面将对象赋值的过程就是一个浅拷贝过程,浅拷贝它拷贝的是对象的索引,拷贝后的对象与原对象共享一个对象。其最大特点是修改拷贝后对象的值会影响到原对象的值。
深拷贝则是完全的、彻彻底底的将对象复制一份,复制之后的对象与原对象相互独立,互不影响。其最大特点与浅拷贝相反,即修改拷贝后对象的值不会影响到原对象的值。
1、浅拷贝
1.1、Object.assign()
1.1.1、Object.assign()
方法属于浅拷贝过程:
const obj3 = { a: 1, b: { b1: 2.1, b2: 2.2}, c: 3, };
const obj4 = Object.assign({}, obj3);
obj4.b.b1 = 'change';
console.log(obj3); // {a: 1, b: {b1: "change", b2: 2.2}, c: 3}
console.log(obj4); // {a: 1, b: {b1: "change", b2: 2.2}, c: 3}
可以看出当改变obj4
中b1
的值时,obj3
的也随之改变。
1.1.2、 需要注意的是Object.assign()
可以实现对象结构深度为一层的深拷贝:
const obj5 = { a: 1, b: 2, c: 3, };
const obj6 = Object.assign({}, obj5);
obj6.b = 'change';
console.log(obj5); // {a: 1, b: 2, c: 3}
console.log(obj6); // {a: 1, b: "change", c: 3}
其中obj5
对象结构的深度只有一层,obj6
对象是由Object.assign()
复制生成,在修改obj6
的b
值之后,会发现obj5
对象没有变化。
2、深拷贝
深拷贝的实现原理就是将对象中的每一个基本数据类型都复制一份到新建的对象中。
深拷贝的实现代码:
思路:对于要拷贝的数据,如果是基本数据类型,直接返回;如果是引用数据类型,则遍历数组或对象中的每一项并赋值给一个新建的数组或对象,如果被遍历的数组或对象元素为引用数据类型,则继续对该引用数据进行循环遍历,如此处理,直到将待拷贝数据中的每一个基本数据类型都复制到新建的对象中为止。
function deepClone(origin){
// 判断需要深度克隆的对象是否是基本数据类型
if(typeof origin === 'object'){
// 判断深度克隆的对象是对象(狭义上的对象)还是数组
let copy;
if(origin instanceof Array){
copy = [];
for(let i in origin){
copy.push(deepClone(origin[i])); // 通过递归实现深层克隆
}
}else{
copy = {};
for(let i in origin){
copy[i] = deepClone(origin[i]); // 通过递归实现深层克隆
}
}
return copy
}else{
return origin
}
}
通过一些简单的例子验证:
测试例子1:
let x = 1;
let xCopy = deepClone(x);
对深拷贝后的对象进行修改:
xCopy = 2;
测试例子2:
let y = [1, 2, 3];
let yCopy = deepClone(y);
对深拷贝后的对象进行修改:
yCopy[0] = 'a';
yCopy[1] = 'b';
测试例子3:
let z = [1, 2, [3, 4]];
let zCopy = deepClone(z);
对深拷贝后的对象进行修改:
zCopy[0] = 'a';
zCopy[2] = 'b';
测试例子4:
let w = {a:1, b:2, c:[3, 4, 5]};
let wCopy = deepClone(w);
对深拷贝后的对象进行修改:
wCopy.a = 11;
wCopy.c = [33, 44, 55];
参考文献
[1] 关于JavaScript的浅拷贝和深拷贝
[2] 也来谈一谈js的浅复制和深复制
[3] js深拷贝和浅拷贝