JavaScript中的深拷贝与浅拷贝
字数 651 2025-11-03 08:33:38

JavaScript中的深拷贝与浅拷贝

描述
在JavaScript中,深拷贝和浅拷贝是处理对象复制的两种不同方式。浅拷贝只复制对象的引用,不复制对象本身,新旧对象共享同一块内存地址。深拷贝则是创建一个全新的对象,并递归复制原对象的所有属性,新旧对象完全独立,互不影响。理解这两种拷贝方式的区别对于避免意外的数据修改至关重要。

知识讲解

1. 基本概念区分

  • 浅拷贝:只复制第一层属性,如果属性是引用类型,复制的只是内存地址
  • 深拷贝:完全复制整个对象结构,包括所有嵌套的引用类型属性

2. 赋值、浅拷贝、深拷贝的对比

让我们先创建一个测试对象:

const originalObj = {
  name: "小明",
  age: 20,
  hobbies: ["篮球", "游泳"],
  address: {
    city: "北京",
    district: "海淀区"
  }
};

赋值操作(不是拷贝):

const assignedObj = originalObj;
assignedObj.name = "小红";
console.log(originalObj.name); // "小红" - 原对象也被修改了

3. 浅拷贝的实现方式

方法一:Object.assign()

const shallowCopy1 = Object.assign({}, originalObj);
shallowCopy1.name = "小刚"; // 修改基本类型属性
console.log(originalObj.name); // "小明" - 原对象未受影响

shallowCopy1.hobbies.push("读书"); // 修改嵌套的引用类型属性
console.log(originalObj.hobbies); // ["篮球", "游泳", "读书"] - 原对象被影响了!

方法二:展开运算符

const shallowCopy2 = {...originalObj};
shallowCopy2.address.city = "上海";
console.log(originalObj.address.city); // "上海" - 原对象被影响了!

4. 深拷贝的实现方式

方法一:JSON.parse(JSON.stringify())(最简单但有限制)

const deepCopy1 = JSON.parse(JSON.stringify(originalObj));
deepCopy1.hobbies.push("绘画");
console.log(originalObj.hobbies); // ["篮球", "游泳"] - 原对象不受影响

局限性

const problemObj = {
  date: new Date(),
  func: function() {},
  undefined: undefined,
  infinity: Infinity,
  regex: /abc/gi
};

const problematicCopy = JSON.parse(JSON.stringify(problemObj));
console.log(problematicCopy);
// date变成字符串,function和undefined丢失,Infinity变成null

方法二:手写递归深拷贝函数

function deepClone(obj, hash = new WeakMap()) {
  // 处理基本类型和null
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  
  // 处理循环引用
  if (hash.has(obj)) {
    return hash.get(obj);
  }
  
  // 处理日期对象
  if (obj instanceof Date) {
    return new Date(obj);
  }
  
  // 处理正则表达式
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }
  
  // 处理数组
  if (Array.isArray(obj)) {
    const result = [];
    hash.set(obj, result);
    obj.forEach(item => {
      result.push(deepClone(item, hash));
    });
    return result;
  }
  
  // 处理普通对象
  const result = {};
  hash.set(obj, result);
  Object.keys(obj).forEach(key => {
    result[key] = deepClone(obj[key], hash);
  });
  
  return result;
}

5. 测试深拷贝函数

const testObj = {
  name: "测试",
  nested: {
    array: [1, 2, { value: 3 }]
  }
};

// 创建循环引用
testObj.self = testObj;

const clonedObj = deepClone(testObj);
clonedObj.nested.array.push(4);

console.log(testObj.nested.array); // [1, 2, {value: 3}] - 原对象不受影响
console.log(clonedObj.self === clonedObj); // true - 循环引用正确处理

6. 实际应用场景

适合浅拷贝的情况

  • 对象结构简单,没有嵌套引用类型
  • 只需要第一层属性的独立副本
  • 性能要求较高,数据量较大

适合深拷贝的情况

  • 需要完全独立的对象副本
  • 对象结构复杂,有多层嵌套
  • 需要修改副本而不影响原对象

总结
深拷贝和浅拷贝是JavaScript中重要的概念。在实际开发中,应根据具体需求选择合适的拷贝方式。对于简单场景可以使用JSON方法,对于复杂场景建议使用成熟的工具库(如Lodash的_.cloneDeep)或自己实现完整的深拷贝函数。

JavaScript中的深拷贝与浅拷贝 描述 在JavaScript中,深拷贝和浅拷贝是处理对象复制的两种不同方式。浅拷贝只复制对象的引用,不复制对象本身,新旧对象共享同一块内存地址。深拷贝则是创建一个全新的对象,并递归复制原对象的所有属性,新旧对象完全独立,互不影响。理解这两种拷贝方式的区别对于避免意外的数据修改至关重要。 知识讲解 1. 基本概念区分 浅拷贝:只复制第一层属性,如果属性是引用类型,复制的只是内存地址 深拷贝:完全复制整个对象结构,包括所有嵌套的引用类型属性 2. 赋值、浅拷贝、深拷贝的对比 让我们先创建一个测试对象: 赋值操作 (不是拷贝): 3. 浅拷贝的实现方式 方法一:Object.assign() 方法二:展开运算符 4. 深拷贝的实现方式 方法一:JSON.parse(JSON.stringify()) (最简单但有限制) 局限性 : 方法二:手写递归深拷贝函数 5. 测试深拷贝函数 6. 实际应用场景 适合浅拷贝的情况 : 对象结构简单,没有嵌套引用类型 只需要第一层属性的独立副本 性能要求较高,数据量较大 适合深拷贝的情况 : 需要完全独立的对象副本 对象结构复杂,有多层嵌套 需要修改副本而不影响原对象 总结 深拷贝和浅拷贝是JavaScript中重要的概念。在实际开发中,应根据具体需求选择合适的拷贝方式。对于简单场景可以使用JSON方法,对于复杂场景建议使用成熟的工具库(如Lodash的_ .cloneDeep)或自己实现完整的深拷贝函数。