深浅拷贝(入门篇)
👉阿勇的博客👈
深拷贝与浅拷贝的区别
在我们编写代码的过程中,会有这么一种情况,当我们定义了一个变量 A ,当某一时间段,我们又声明了一个变量 B ,把A的值赋值给变量 B(let B = A)。 这里分两种情况:
情况一: 如果改变 B 的值,引起了 A 的变化,则我们称之为浅拷贝。(其实拷贝的是A的内存地址)
情况二: 如果改变 B 的值,没有引起 A 的变化,则我们称之为深拷贝。(自食其力)
浅拷贝
举例说明:
let arr1 = [1,2,3,4,5];
let arr2 = arr1; // [1,2,3,4,5]
arr2[0] = 6;
console.log(arr1); // [ 6, 2, 3, 4, 5 ]
console.log(arr2); // [ 6, 2, 3, 4, 5 ]
我想的是,通过 arr2 的赋值,只想改变 arr2 的值,但是 arr1 中也跟着改变了,这里其实不难理解,因为 arr2 复制的是 arr1 的内存地址,所以 arr2 和 arr1 指向同一个值。
深拷贝
那么怎样才能在不影响 A 的情况下,改变 B 的值呢?
这里先来演示几个刚开始我认为的深拷贝。
slice方法完成深拷贝
let arr1 = [1,2,3,4,5];
let arr2 = arr1.slice(); // [1,2,3,4,5]
arr2[0] = 6;
console.log(arr1); // [ 1, 2, 3, 4, 5 ]
console.log(arr2); // [ 6, 2, 3, 4, 5 ]
concat方法完成深拷贝
let arr1 = [1,2,3,4,5];
let arr2 = arr1.concat(); // [1,2,3,4,5]
arr2[0] = 6;
console.log(arr1); // [ 1, 2, 3, 4, 5 ]
console.log(arr2); // [ 6, 2, 3, 4, 5 ]
扩展运算符完成深拷贝
let arr1 = [1,2,3,4,5];
let arr2 = arr1.concat(); // [1,2,3,4,5]
arr2[0] = 6;
console.log(arr1); // [ 1, 2, 3, 4, 5 ]
console.log(arr2); // [ 6, 2, 3, 4, 5 ]
::: danger
以上三种方法看似都很不错,如果看到这里感觉这就是深拷贝了,那真是跳进了一个大坑。
:::
如果出现下边这种情况,上面的方法似乎不太行了 ↓
let arr1 = [1,[2,3,4,5],6,7];
let arr2 = arr1.concat(); // [1,[2,3,4,5],6,7]
arr2[1][0] = 8;
console.log(arr1); // [ 1, [ 8, 3, 4, 5 ], 6, 7 ]
console.log(arr2); // [ 1, [ 8, 3, 4, 5 ], 6, 7 ]
清楚的发现,刚才我们的方法不生效了,这里我理解的为 slice、concat、扩展运算符只能是深拷贝第一层,当类型中包含对象时就不好使了,实际上也是浅拷贝。
其他两种方式效果同上,大家自行尝试。
真正的深拷贝
- 方法一:通过 JSON对象
let arr1 = [1,[2,3,4,5],6,7];
let arr2 = JSON.parse(JSON.stringify(arr1)); // [1,[2,3,4,5],6,7]
arr2[1][0] = 8;
console.log(arr1); // [ 1, [ 2, 3, 4, 5 ], 6, 7 ]
console.log(arr2); // [ 1, [ 8, 3, 4, 5 ], 6, 7 ]
- 方法二:手写一个原生的深拷贝函数
function deepCopy(obj) {
// 判断传入的 obj 是否为数组对象
let copyValue = Array.isArray(obj) ? [] : {};
if (obj && typeof obj == 'object') {
for (key in obj) {
// 判断 obj 是否存在 key 属性
if (obj.hasOwnProperty(key)) {
// 如果 obj[key] 为一个对象,则递归输出
if (obj[key] && typeof obj[key] == 'object') {
copyValue[key] = deepCopy(obj[key]);
} else {
copyValue[key] = obj[key];
}
}
}
}
return copyValue;
}
let arr1 = [1, [2, 3, 4, 5], 6, 7];
let arr2 = deepCopy(arr1); // [1, [2, 3, 4, 5], 6, 7]
arr2[1][0] = 8;
console.log(arr1); // [ 1, [ 2, 3, 4, 5 ], 6, 7 ]
console.log(arr2); // [ 1, [ 8, 3, 4, 5 ], 6, 7 ]
总结
深浅拷贝在每种语言中都会涉及到,掌握还是很有必要的。起码当我们遇到此类问题的时候无从下手。这也是面试中经常问到的一个点。正所谓知其然知其所以然。

浙公网安备 33010602011771号