JavaScript浅拷贝和深拷贝完全解析(别再乱拷贝了!)
前言
在 JavaScript 开发中,对象拷贝是一个绕不开的核心话题。无论是状态管理、数据缓存还是函数参数传递,我们都需要谨慎处理数据的复制方式,避免因引用共享导致意外的数据修改。
本文将结合实际开发场景,详细拆解浅拷贝与深拷贝的区别、实现方式及适用场景。
一、拷贝的本质:引用 vs 新对象
JavaScript中的对象(包括数组、函数等)属于引用类型,变量存储时存储的并非是对象本身,而是对象的引用地址。
- 原始类型拷贝:直接复制值,两个变量互不影响。
- 引用类型拷贝:如果只是简单赋值(
const newObj = obj),本质是复制了对象的引用地址,新旧对象指向同一块内存,修改其中一个会直接影响另一个。
真正的 “拷贝”,是基于原对象创建一个新对象,使新对象与原对象在内存上相互独立。根据拷贝的深度,又分为浅拷贝和深拷贝。
二、浅拷贝:只复制第一层
浅拷贝(Shallow Copy)只会复制对象的第一层属性,如果属性值是引用类型(如子对象、数组),则仍然复制其引用地址。
核心特点
- 新对象的第一层属性与原对象隔离。
- 嵌套的子对象 / 数组仍共享引用,修改子对象会影响原对象。
常用实现方式
1. 数组专用方法
Array.prototype.slice(0):创建原数组的浅拷贝。const arr = [1, 2, { a: 3 }]; const newArr = arr.slice(0); newArr[2].a = 4; // 会修改原数组的 arr[2].a扩展运算符
...:ES6 新增,语法更简洁。const newArr = [...arr];
Array.prototype.concat():合并数组并返回新数组。const newArr = [].concat(arr);
在一个空数组后拼接原数组并赋值给新数组,这个新数组就可以说是由原数组拷贝所得到的。
toReversed()与reverse()方法:
toReversed() 反转数组,得到一个新数组;reverse() 反转数组,改变原数组。通过这两个方法组合,我们就可以实现浅拷贝的效果。
const newArr=arr.toReversed().reverse()
2. 对象通用方法
Object.assign({}, obj):将原对象的可枚举属性复制到新对象。const obj = { a: 1, b: { c: 2 } }; const newObj = Object.assign({}, obj); newObj.b.c = 3; // 原对象 obj.b.c 也会变为 3Object.assign():是 JavaScript 中用于对象属性复制与合并的核心方法,它能将一个或多个源对象的可枚举属性复制到目标对象中,并返回修改后的目标对象。核心语法
Object.assign(target, ...sources)
target是接受属性的目标修改对象,...sources是一个或多个提供属性的对象。
代码示例:
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
Object.assign(target, source);
console.log(target); // { a: 1, b: 4, c: 5 }
若目标对象与源对象存在同名属性,后面的源对象属性会覆盖前面的。
三、深拷贝:彻底隔离数据
深拷贝(Deep Copy)会递归复制对象的所有层级,包括嵌套的子对象、数组等,最终得到一个与原对象完全独立的新对象,修改新对象不会对原对象产生任何影响。
核心特点
- 新对象与原对象在内存上完全隔离。
- 无论修改哪一层属性,都不会影响对方。
常用实现方式
1.JSON.parse(JSON.stringify(obj))
这是最常用的 “民间” 深拷贝方案,先将对象序列化为 JSON 字符串,再反序列化为新对象。
const obj = { a: 1, b: { c: 2 } };
const newObj = JSON.parse(JSON.stringify(obj));
newObj.b.c = 3; // 原对象不受影响
局限性:无法处理函数、Symbol、BigInt、undefined、NaN、Infinity、function 等特殊类型,且会丢失原型链。
2.structuredClone()
浏览器原生 API,现代浏览器和 Node.js 17+ 支持,是更标准的深拷贝方案。
const newObj = structuredClone(obj);
局限性:无法拷贝函数、Symbol,也不能处理带有循环引用的对象。
四、总结
- 浅拷贝:高效、轻量,适合处理扁平结构数据,但要注意嵌套引用的问题。
- 深拷贝:彻底隔离数据,避免副作用,但性能开销更大。
- 核心原则:根据数据结构和业务场景选择合适的拷贝方式,避免过度设计。
在实际开发中,我们应优先使用浅拷贝保证性能,只有在数据结构复杂且需要完全隔离时,才考虑深拷贝。理解拷贝的本质,是写出健壮、可维护的 JavaScript 代码的关键一步。
到此这篇关于JavaScript浅拷贝和深拷贝完全解析的文章就介绍到这了,更多相关JS浅拷贝和深拷贝内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
详解JavaScript对数组操作(添加/删除/截取/排序/倒序)
这篇文章主要介绍了JavaScript对数组操作,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2019-04-04
两个JavaScript中的特殊值null和undefined详解
Null和Undefined是JavaScript中非常基础和重要的概念,理解它们的含义、特点和使用方式对于避免出现错误和编写健壮的应用程序非常重要,这篇文章主要介绍了两个JavaScript中的特殊值null和undefined详解,需要的朋友可以参考下2023-06-06


最新评论