JavaScript 中的深拷贝和浅拷贝

79 阅读2分钟

拷贝:把对象拷贝给一个新的对象,开发中我们经常需要复制一个对象

浅拷贝

如果直接赋值,则复制的是地址,修改任何一个对象,另一个对象都会变化

  • 如果是基本数据类型拷贝值
  • 如果是引用数据类型拷贝的是地址
  • 简单理解:如果是单层对象,没问题,如果有多层就有问题,还是会影响原来对象

在 JavaScript 中,浅拷贝可以通过几种方式实现:

1、对象扩展运算符(...):使用对象扩展运算符可以将一个对象中的所有属性复制到另一个对象中。

const sourceObject = { name: 'John', age: 30 };
const targetObject = { ...sourceObject };

2、Object.assign() 方法:将一个或多个源对象的所有可枚举属性复制到目标对象中,并返回目标对象。


const sourceObject = { name: 'John', age: 30 };
const targetObject = Object.assign({}, sourceObject);

3、数组的 slice() 和 concat() 方法:对数组进行浅拷贝时,可以使用 slice() 或 concat() 方法。

const sourceArray = [1, 2, 3];
const targetArray = sourceArray.slice();


const targetArray = sourceArray.concat();

深拷贝

拷贝多层,不再拷贝地址

常见方法:

  1. 通过 JSON 序列化实现(缺点:function 或 undefined等,在序列化过程中会被忽略)

使用 JSON 序列化和反序列化:

将原始对象序列化为 JSON 字符串,然后再反序列化为新对象。但是这种方法只能用于简单的对象,不能用于包含函数、正则表达式等特殊数据类型的对象。

const sourceObject = { name: 'John', age: 30, address: { street: '123 Main St.' } };
const jsonString = JSON.stringify(sourceObject);
const targetObject = JSON.parse(jsonString);

  1. 通过递归实现,递归复制所有属性:使用递归函数遍历对象或数组的所有属性,并将它们复制到新的对象或数组中。
// 通过递归实现

function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  
  let clone = Array.isArray(obj) ? [] : {};
  
  for (let key in obj) {
    if (Object.hasOwnProperty.call(obj, key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  
  return clone;
}

const sourceObject = { name: 'John', age: 30, address: { street: '123 Main St.' } };
const targetObject = deepClone(sourceObject);

3、lodash库 实现深拷贝,比较常用(缺点:要引用外部数据)

lodash库提供了一个函数cloneDeep来实现深拷贝。该函数可以递归地复制对象及其嵌套的子对象,创建一个全新的、与原始对象完全独立的副本。

例如,要对一个对象进行深拷贝,可以这样使用cloneDeep函数:

// 深拷贝

const _ = require('lodash');

const obj = {
  a: 1,
  b: {
    c: 2,
    d: [3, 4],
    e: {
      f: 5
    }
  }
};

const newObj = _.cloneDeep(obj);

newObj.b.c = 6;
console.log(obj.b.c); // 输出2,原始对象未受影响
console.log(newObj.b.c); // 输出6,新对象已被修改

在使用时,先定义了一个包含嵌套结构的对象obj,然后使用cloneDeep函数将其深拷贝到一个全新的对象newObj中,最后修改newObj的某个属性,并验证原始对象是否受到影响。