深浅拷贝(入门篇)

👉阿勇的博客👈

深拷贝与浅拷贝的区别

在我们编写代码的过程中,会有这么一种情况,当我们定义了一个变量 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 ]

清楚的发现,刚才我们的方法不生效了,这里我理解的为 sliceconcat扩展运算符只能是深拷贝第一层,当类型中包含对象时就不好使了,实际上也是浅拷贝。

其他两种方式效果同上,大家自行尝试。

真正的深拷贝

  • 方法一:通过 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 ]

总结

深浅拷贝在每种语言中都会涉及到,掌握还是很有必要的。起码当我们遇到此类问题的时候无从下手。这也是面试中经常问到的一个点。正所谓知其然知其所以然。

posted @ 2021-09-23 10:28  ayong6  阅读(107)  评论(0)    收藏  举报