JavaScript拷贝大作战:浅拷贝vs深拷贝

简介: JavaScript拷贝大作战:浅拷贝vs深拷贝

说在前面

在现代JavaScript开发中,对象和数组的拷贝是一项常见但也容易被忽视的任务。然而,简单的赋值操作可能会导致意想不到的结果,因为它们只是创建了一个指向原始数据的引用。为了解决这个问题,JavaScript提供了深拷贝和浅拷贝两种拷贝方式。浅拷贝仅复制对象的引用,而深拷贝则创建一个全新的对象,完全独立于原始对象。本文将详细介绍这两种拷贝方式,包括它们的定义、应用场景以及如何在JavaScript中实现它们。无论您是初学者还是有一定经验的开发人员,本文都将帮助您更好地理解和应用深拷贝和浅拷贝,提升代码的可靠性和灵活性。让我们一起深入探索拷贝的世界吧!

深拷贝和浅拷贝的差异

深拷贝和浅拷贝都有各自适用的场景。深拷贝适用于需要完全独立的副本,并保持与原始对象的分离的情况。而浅拷贝适用于需要共享数据、降低内存占用和提高性能的情况。根据具体的需求和应用场景,选择适当的拷贝方式是至关重要的。

深拷贝

复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针和堆内存中的对象。(修改拷贝对象中的应用类型属性值时,原对象不会随着变化

深拷贝是指创建一个完全独立于原始对象的副本,包括对象的所有嵌套属性和数组元素。深拷贝会递归地遍历原始对象,将其所有属性和元素复制到新的对象中,确保新对象与原始对象完全分离。这意味着对深拷贝创建的对象进行修改不会影响原始对象。

使用场景
  • 当需要在两个独立的对象之间共享或传递数据时,使用深拷贝可以确保数据的独立性,避免意外的共享和修改。
  • 当需要对对象进行修改或转换,但不希望影响原始对象时,可以使用深拷贝创建一个可安全操作的副本。

浅拷贝

复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针,不复制堆内存中的对象。(修改拷贝对象中的应用类型属性值时,原对象也会随着变化

浅拷贝仅复制对象的引用,而不复制对象的实际值。换句话说,浅拷贝创建了一个新的对象,但该对象与原始对象共享相同的属性和元素。修改浅拷贝对象的属性或元素会影响原始对象。

使用场景
  • 当需要在两个对象之间共享数据,且希望对其中一个对象进行修改时,可以使用浅拷贝。这样做可以减少内存占用和提高性能,因为不需要创建完全独立的副本。
  • 当只需要访问对象的一部分属性或元素时,浅拷贝可以提供便利,避免复制整个对象的开销。

JS实现

浅拷贝

1、直接赋值
const originalObj = { name: 'John', age: 30 };
const newObj = originalObj;
newObj.name = 'jerry';
console.log(originalObj);

2、扩展运算符

使用扩展运算符可以快速简洁地进行对象和数组的浅拷贝。它会创建一个新的对象或数组,并将原始对象或数组的所有属性和元素复制到新的对象或数组中。

const originalObj = { name: 'John', age: 30, address:{city: 'Guangzhou'} };
const newObj = { ...originalObj };
newObj.address.city = 'Beijing';
console.log(originalObj);

const originalArr = [{ name: 'John'}];
const newArr = [...originalArr];
newArr[0].name = 'Jerry';
console.log(newArr);

3、Object.assign()

Object.assign() 方法可以将一个或多个源对象的属性复制到目标对象中,并返回目标对象。这个方法也可以用于浅拷贝对象。

const originalObj = { name: 'John', age: 30, address:{city: 'Guangzhou'} };
const newObj = Object.assign({}, originalObj);
newObj.address.city = 'Beijing';
console.log(newObj);

4、Array.slice()

对于数组,可以使用 Array.slice() 方法进行浅拷贝。该方法返回一个新的数组,包含原始数组中指定范围的元素。

const originalArr = [{ name: 'John'}];
const newArr = originalArr.slice();
newArr[0].name = 'Jerry';
console.log(newArr);

5、Array.concat()

Array.concat() 方法可以将两个或多个数组合并为一个新数组,并返回这个新数组。使用空参数调用 concat() 方法,可以实现对数组的浅拷贝。

const originalArr = [{ name: 'John'}];
const newArr = [].concat(originalArr);
newArr[0].name = 'Jerry';
console.log(newArr);

深拷贝

1、JSON.parse(JSON.stringify())

该方法是目前最常用的深拷贝方法之一。它基于 JSON 格式序列化和反序列化对象,将对象转换成字符串再转回对象,达到深拷贝的目的。

const originalObj = { 
  name: 'John', 
  age: 30, 
  address: { 
    city: 'Beijing', 
    country: 'China' 
  } 
};
const newObj = JSON.parse(JSON.stringify(originalObj));
newObj.address.city = 'Guangzhou';
console.log('originalObj:',originalObj); 
console.log('newObj:',newObj);

局限

  • 无法拷贝函数、正则表达式等特殊对象。
  • 无法处理循环引用的情况。

2、手动递归拷贝方法

这种方法基于手动递归复制对象及其属性,直到所有属性都是基本数据类型为止。

function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  const newObj = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepClone(obj[key]);
    }
  }
  return newObj;
}
const originalObj = { 
  name: 'John', 
  age: 30, 
  address: { 
    city: 'Beijing', 
    country: 'China' 
  } 
};
const newObj = deepClone(originalObj);
newObj.address.city = 'Guangzhou';
console.log('originalObj:',originalObj); 
console.log('newObj:',newObj);

局限

  • 无法拷贝循环引用的情况。
3、第三方库

除了以上两种方法,还有一些成熟的第三方库可以实现深拷贝,如 Lodash、jQuery 等。这些库提供了更为全面和高效的深拷贝功能,可以满足各种复杂对象的拷贝需求。

const originalObj = { 
  name: 'John', 
  age: 30, 
  address: { 
    city: 'Beijing', 
    country: 'China' 
  } 
};
const newObj = _.cloneDeep(originalObj);
newObj.address.city = 'Guangzhou';
console.log(newObj);

局限

  • 使用第三方库会增加项目的依赖和代码体积

公众号

关注公众号『前端也能这么有趣』,获取更多新鲜内容。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

目录
相关文章
|
3月前
|
JSON 缓存 JavaScript
拷贝对象,拷贝快乐:揭开JavaScript中拷贝的神奇面纱
拷贝对象,拷贝快乐:揭开JavaScript中拷贝的神奇面纱
|
15天前
|
JavaScript 前端开发
js中浅拷贝和深拷贝的区别
js中浅拷贝和深拷贝的区别
21 1
|
1月前
|
JavaScript 前端开发 API
javascript中的浅拷贝和深拷贝
javascript中的浅拷贝和深拷贝
|
3月前
|
前端开发 JavaScript 定位技术
Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较
Flutter vs 前端 杂谈:SliverAppBar、手动实现Appbar、前端Html+JS怎么实现滚动变化型Appbar - 比较
33 0
|
3月前
|
JavaScript 前端开发
Js中浅拷贝和深拷贝有什么区别,如何实现?
在 JavaScript 中,浅拷贝(Shallow Copy)和深拷贝(Deep Copy)是两种常见的数据拷贝方式,它们的区别在于拷贝的程度
22 0
|
3月前
|
JavaScript 前端开发
JavaScript浅拷贝和深拷贝
JavaScript浅拷贝和深拷贝
|
3月前
|
JavaScript 前端开发
js中浅拷贝和深拷贝的区别
js中浅拷贝和深拷贝的区别
27 0
|
3月前
|
JSON 前端开发 JavaScript
【面试题】JavaScript 深拷贝和浅拷贝 高级
【面试题】JavaScript 深拷贝和浅拷贝 高级
|
5月前
|
存储 JSON JavaScript
JavaScript深拷贝与浅拷贝
JavaScript深拷贝与浅拷贝
22 0
|
6月前
|
存储 JavaScript 前端开发
带你读《现代Javascript高级教程》十七、JavaScript深拷贝与浅拷贝(1)
带你读《现代Javascript高级教程》十七、JavaScript深拷贝与浅拷贝(1)