JavaScript中的深拷贝与浅拷贝

111 阅读4分钟

概述

深浅拷贝是指在计算机程序中,对于一个对象(通常是复杂对象),将其拷贝到另一个对象时,会对原对象的内容进行复制,生成一个新的对象,然后将新的对象传递给被拷贝对象使用。深浅拷贝的区别在于,当原对象包含了其他对象或者嵌套的数据结构时,深拷贝会递归地拷贝所有相关对象和数据,而浅拷贝则只是复制原对象的指针,指向同样的内存地址,这意味着如果修改了拷贝对象中的嵌套对象,则原对象也会被修改。

深拷贝

具体来说,深拷贝会创建一个全新的对象,包括其嵌套的对象和属性。这个新对象的修改不会影响到原对象。常见的实现深拷贝的方式包括:

以下是一些常见的 JavaScript 深拷贝技巧:

  1. 使用 JSON 序列化和反序列化

JavaScript 的内置对象 JSON 提供了 JSON.stringify() 和 JSON.parse() 方法,可以将对象序列化为 JSON 字符串,再将其反序列化为新对象。这个方法非常简单,适用于大多数对象,但它有一些限制:

  • 无法复制函数和循环引用
  • 会丢失特殊的对象属性,如 Map,Set,Date 等

示例代码:

const obj = { name: 'John', age: 30, hobbies: ['reading', 'traveling'] };
const newObj = JSON.parse(JSON.stringify(obj));
  1. 使用递归

递归是深拷贝的另一种方法,它会遍历整个对象,复制每个子对象并将其添加到新对象中。递归方法可以复制所有类型的对象,包括函数和循环引用,但是当对象过于复杂时,可能会导致性能问题。

示例代码:

function deepClone(obj) {
  let clone = {};
  for (let i in obj) {
    if (obj[i] != null && typeof obj[i] == 'object') {
      clone[i] = deepClone(obj[i]);
    } else {
      clone[i] = obj[i];
    }
  }
  return clone;
}

const obj = { name: 'John', age: 30, hobbies: ['reading', 'traveling'] };
const newObj = deepClone(obj);
  1. 使用第三方库

许多第三方库,如 Lodash 和 jQuery,提供了深拷贝函数。这些函数通常提供更多选项和更好的性能,但是需要在项目中引入额外的依赖。

示例代码(使用 Lodash):

const _ = require('lodash');
const obj = { name: 'John', age: 30, hobbies: ['reading', 'traveling'] };
const newObj = _.cloneDeep(obj);

浅拷贝

在 JavaScript 中,浅拷贝是指将一个对象的属性复制到另一个对象中,这两个对象之间仍然存在引用关系,也就是说,如果您更改其中一个对象的属性,另一个对象的属性也会发生相应的更改。

以下是一些常见的 JavaScript 浅拷贝技巧:

  1. 使用对象展开运算符

对象展开运算符可以将一个对象的所有属性展开为一个新对象,您可以使用这个新对象来创建一个浅拷贝。对象展开运算符不会复制原始对象的方法,只会复制它的属性。

示例代码:

const obj = { name: 'John', age: 30, hobbies: ['reading', 'traveling'] };
const newObj = { ...obj };
  1. 使用 Object.assign()

Object.assign() 方法将一个或多个源对象的属性复制到目标对象中。该方法返回目标对象。Object.assign() 方法会对目标对象进行修改,并返回目标对象。如果目标对象与源对象具有相同的属性,则源对象中的属性会覆盖目标对象中的属性。

示例代码:

const obj = { name: 'John', age: 30, hobbies: ['reading', 'traveling'] };
const newObj = Object.assign({}, obj);
  1. 使用数组的 slice() 方法

如果要浅拷贝一个数组,可以使用数组的 slice() 方法。slice() 方法返回一个新数组,包含从开始到结束(不包括结束)选择的数组的元素。使用空参数列表调用 slice() 方法可以复制整个数组。

示例代码:

const arr = [1, 2, 3, 4];
const newArr = arr.slice();

需要注意的是,以上三种方法都只能进行浅拷贝,如果源对象或数组中包含嵌套对象或数组,则嵌套对象或数组的引用将保留在新对象或数组中。如果您需要进行深拷贝,请使用深拷贝方法,如 JSON.parse(JSON.stringify(obj)) 或 Lodash 的 _.cloneDeep()。