likes
comments
collection
share

深拷贝和浅拷贝的区别及应用场景详解

作者站长头像
站长
· 阅读数 12

标题:深拷贝和浅拷贝的区别及应用场景详解

引言

在前端开发中,深拷贝和浅拷贝是处理对象和数组复制时常用的两种方式。它们的实现和应用场景有着明显的区别,对于开发者来说了解这些区别是非常重要的。本文将详细解释深拷贝和浅拷贝的概念,并提供它们在不同场景中的应用示例。

浅拷贝

浅拷贝定义

浅拷贝是指创建一个新的对象或数组,并复制原始对象或数组的值。它们可能共享一些内部数据,但并不共享相同的内存地址。当对新对象或数组进行修改时,不会影响原始对象或数组的值。

浅拷贝的实现方式:

  • 对象:使用Object.assign()、扩展操作符{...}等等。
  • 数组:使用Array.slice()Array.concat()、扩展操作符[...]等等。

例子:

对象拷贝

  • 使用Object.assign()方法进行浅拷贝:
const originalObj = {
  name: "John",
  age: 25
};

const copyObj = Object.assign({}, originalObj);

copyObj.age = 30;

console.log(originalObj.age);  // 输出: 25
console.log(copyObj.age);  // 输出: 30
  • 使用扩展运算符({...})进行浅拷贝:
const originalObj = {
  name: "John",
  age: 25
};

const copyObj = { ...originalObj };

copyObj.age = 30;

console.log(originalObj.age);  // 输出: 25
console.log(copyObj.age);  // 输出: 30

数组的浅拷贝

  • 使用Array.slice()方法进行浅拷贝:
const originalArr = [1, 2, 3];
const copyArr = originalArr.slice();

copyArr[0] = 10;

console.log(originalArr);  // 输出: [1, 2, 3]
console.log(copyArr);  // 输出: [10, 2, 3]
  • 使用Array.concat()方法进行浅拷贝:
const originalArr = [1, 2, 3];
const copyArr = originalArr.concat();

copyArr[0] = 10;

console.log(originalArr);  // 输出: [1, 2, 3]
console.log(copyArr);  // 输出: [10, 2, 3]
  • 使用扩展运算符([...])进行浅拷贝:
const originalArr = [1, 2, 3];
const copyArr = [...originalArr];

copyArr[0] = 10;

console.log(originalArr);  // 输出: [1, 2, 3]
console.log(copyArr);  // 输出: [10, 2, 3]

浅拷贝的应用场景

  • 浅拷贝适用于复制简单对象,(简单对象指的是对象的属性或数组的元素是原始类型的数据,如字符串、数字、布尔值等。这些原始类型的数据在内存中是独立存储的,并不会相互影响)并且在部分属性修改或只读副本等场景中使用。当涉及到复杂结构或需要递归复制对象的情况时,深拷贝更常用。

注意点

  • 对于包含嵌套对象或数组的复杂结构,浅拷贝只复制了内部对象的引用,而没有对其进行递归复制。在这种情况下,深拷贝更适合确保复制所有嵌套对象和数组的内容,以避免原始对象的更改。

深拷贝

深拷贝定义

深拷贝是指创建一个新的对象或数组,并递归地复制原始对象或数组的所有嵌套对象和数组。新对象或数组是完全独立的,与原始对象或数组没有任何关联,对新对象或数组的修改不会影响原始对象或数组。

深拷贝的实现方式

  • 对象和数组:使用JSON.parse(JSON.stringify())方法对对象或数组进行序列化和反序列化。(序列化是将对象或数组转换为字符串的过程,而反序列化则是将字符串转换回对象或数组的过程。通过将对象或数组序列化为字符串,再通过解析字符串来创建新的对象或数组,可以实现深拷贝
const originalObj = {
  name: "John",
  age: 25,
  hobbies: ["抽烟", "喝酒", "烫头"],
  address: {
    city: "北京",
    country: "中国",
    coordinates: {
      latitude: 39.9042,
      longitude: 116.4074
    }
  }
};

const copyObj = JSON.parse(JSON.stringify(originalObj));

copyObj.age = 30;
copyObj.hobbies.push("吹牛");
copyObj.address.city = "上海";
copyObj.address.coordinates.latitude = 31.2304;  // 将纬度改上海的坐标
copyObj.address.coordinates.longitude = 121.4737;  // 将经度改上海的坐标

console.log(originalObj.age);  // 输出: 25
console.log(originalObj.hobbies);  // 输出: ["抽烟", "喝酒", "烫头"]
console.log(originalObj.address.city);  // 输出: "北京"
console.log(originalObj.address.coordinates.latitude);  // 输出: 39.9042
console.log(originalObj.address.coordinates.longitude);  // 输出: 116.4074

console.log(copyObj.age);  // 输出: 30
console.log(copyObj.hobbies);  // 输出: ["抽烟", "喝酒", "烫头","吹牛"]
console.log(copyObj.address.city);  // 输出: "上海"
console.log(copyObj.address.coordinates.latitude);  // 输出: 31.2304
console.log(copyObj.address.coordinates.longitude);  // 输出: 121.4737

梳理

  • 原始对象originalObj包含了三层嵌套的结构。我们通过使用JSON.stringify()将其转化为字符串,再使用JSON.parse()将其转化为新的深拷贝对象copyObj。然后,我们对copyObj进行了一系列修改,包括修改age属性的值、向hobbies数组中添加新的元素、修改address对象中的city属性的值,以及修改coordinates对象中的latitude属性的值。这些修改不会影响原始对象originalObj的值。

JSON.parse(JSON.stringify())方法注意点

  • 通过JSON.parse(JSON.stringify())方法可以实现对三层嵌套对象或数组的深拷贝。请记住,这种方法可能会导致数据类型的变化,比如日期对象会转换为字符串。并且对于大型或复杂的对象,性能可能会受到影响。

深拷贝的应用场景

  • 适用于复制复杂对象或数组,其中对象的属性或数组的元素也是对象或数组,或不希望修改副本后影响原始对象或数组。

注意点

  • 在某些情况下,深拷贝可能会存在限制或问题,如循环引用或函数的拷贝,因此需要根据具体情况进行评估和选择使用深拷贝或浅拷贝。

结论

深拷贝和浅拷贝在JavaScript开发中有着不同的应用场景和实现方式。了解它们的区别对于正确处理对象和数组的复制至关重要。开发者应根据实际需求来选择适合的拷贝方式,以确保代码的正确性和可维护性。