返回

“多维解析”JS中的深拷贝:揭秘浅谈背后的真谛

前端

深入浅出,剥丝抽茧解深拷贝

JavaScript中的数据类型可分为基本类型和引用类型。基本类型包括字符串、数字、布尔值等,它们的值存储在栈内存中;引用类型包括对象、数组、函数等,它们的值存储在堆内存中,通过引用来访问。当对引用类型进行赋值操作时,实际上是将变量的指针指向了堆内存中的对象。

浅拷贝是指对引用类型进行赋值操作时,仅仅复制其指针,指向堆内存中同一块地址。这意味着对浅拷贝副本的修改会影响原始对象,反之亦然。

深拷贝是指对引用类型进行赋值操作时,会在堆内存中重新开辟一块内存地址,将原始对象的值完全复制过来存放起来。这意味

着深拷贝副本与原始对象完全独立,不受互相影响。

实战演练,揭秘深拷贝的多种实现方式

方法一:使用JSON.parse()和JSON.stringify()

const obj = { name: 'John', age: 30 };

// 使用JSON.stringify()将对象转换成JSON字符串
const jsonStr = JSON.stringify(obj);

// 使用JSON.parse()将JSON字符串转换成对象
const newObj = JSON.parse(jsonStr);

console.log(newObj); // { name: 'John', age: 30 }
console.log(obj === newObj); // false

方法二:使用Object.assign()

const obj = { name: 'John', age: 30 };

// 使用Object.assign()将对象的值复制到另一个对象中
const newObj = Object.assign({}, obj);

console.log(newObj); // { name: 'John', age: 30 }
console.log(obj === newObj); // false

方法三:使用递归

function deepCopy(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  if (Array.isArray(obj)) {
    return obj.map(item => deepCopy(item));
  }

  const newObj = {};
  for (const key in obj) {
    newObj[key] = deepCopy(obj[key]);
  }

  return newObj;
}

const obj = { name: 'John', age: 30, hobbies: ['coding', 'reading'] };

const newObj = deepCopy(obj);

console.log(newObj); // { name: 'John', age: 30, hobbies: ['coding', 'reading'] }
console.log(obj === newObj); // false

灵活运用,深拷贝的进阶技巧

情景一:对象包含循环引用

循环引用是指两个或多个对象相互引用,导致无法释放内存的情况。在深拷贝的过程中,如果遇到循环引用,需要特殊处理。可以使用WeakMap或Set来存储已复制过的对象,当再次遇到循环引用时,直接返回WeakMap或Set中存储的对象即可。

情景二:对象包含不可序列化的属性

有些属性,如函数、正则表达式、Symbol等,是不可序列化的。在深拷贝的过程中,遇到不可序列化的属性时,需要特殊处理。可以将不可序列化的属性删除或替换为可序列化的值。

结语

深拷贝在JavaScript中扮演着重要的角色,它可以帮助我们创建对象副本,而不影响原始对象。理解深拷贝的机制和应用场景,可以帮助我们编写出更加可靠和高效的代码。