JavaScript 浅拷贝与深拷贝:实例和最佳实践
在处理 JavaScript 中的对象和数组时,创建数据结构的副本是一个常见的任务。然而,开发人员在选择是创建 浅复制 还是 深复制 时经常会遇到挑战。误解这两种复制的区别可能会导致代码意外产生副作用。让我们来了解一下这些概念、它们的区别以及何时该使用哪种复制。
(此处省略内容)
👉 下载电子书 (eBook) - JavaScript:从ES6到ES2023 (https://qirolab.gumroad.com/l/javascript-from-es2015-to-es2023)
此处省略内容
什么是浅复制?
浅拷贝会创建一个新的对象,其中复制了原始对象的顶层属性(如数字、字符串、布尔类型等)。对于对象属性(如数组或嵌套对象),则只复制了引用,而不是实际的数据。
这意味着新对象虽然有自己的顶级属性副本,但嵌套的对象和数组依然与原始对象共享着。
浅层复制的一个例子
const original = {
name: "Alice",
details: {
age: 25,
city: "Wonderland"
}
};
// 浅复制
const shallowCopy = { ...original };
// 修改浅复制中的嵌套的对象
shallowCopy.details.city = "照镜城";
// 原始对象也被修改了
console.log(original.details.city); // 输出: "照镜城"
全屏进入 还原全屏
如何创建浅复制
- 使用扩展运算符 ...:
const 浅拷贝副本 = { ...原对象 };
进入全屏模式 切换到全屏模式
- 使用
Object.assign()
:
const 浅拷贝 = Object.assign({}, 原始对象);
点击全屏模式;点击退出全屏
虽然这些方法快速且简单,但它们不适用于高度嵌套的对象结构。
……此处省略……
什么是深度复制?
深拷贝会复制原始对象的所有属性及其子属性。这样可以确保副本与原始对象完全独立,修改副本不会影响到原始对象。
特别是当处理嵌套对象或数组等复杂数据结构时,特别是在数据完整性非常关键的情况下,深复制是必不可少的。
深拷贝示例(示例意为例子或范例)
(看看如何实现一个深拷贝)
const original = {
name: "Alice",
details: {
age: 25,
city: "Wonderland"
}
};
// 用JSON方式做了一个深拷贝
const deepCopy = JSON.parse(JSON.stringify(original));
// 修改了深拷贝里的嵌套对象
deepCopy.details.city = "Looking Glass";
// 原始对象没有改变
console.log(original.details.city); // 结果是 "Wonderland"
全屏模式/退出全屏
如何创建一个深拷贝.
- 使用
JSON.stringify()
和JSON.parse()
:
-
首先将对象转换为JSON字符串,然后再将其解析回新的对象。
-
限制包括:
-
无法处理循环引用的情况。
- 忽略掉函数、
undefined
或Symbol
等属性或值。
const originalObject = 原始对象; // 深拷贝原始对象
const deepCopy = JSON.parse(JSON.stringify(originalObject));
请进入全屏
请退出全屏
- 使用库(如)Lodash这样的库提供了强大的深层克隆功能。
const _ = require('lodash');
// 深拷贝原始对象
const 深拷贝 = _.cloneDeep(原始对象);
全屏显示 退出全屏
- 自定义的递归函数:
-
为了实现完全控制,你可以编写一个递归函数来克隆嵌套的对象结构。
-
- *
浅层拷贝和深层拷贝的对比
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
作用域 | 只复制顶级属性。 | 复制所有层级,包括嵌套数据。 |
引用 | 嵌套引用共享。 | 嵌套引用独立。 |
性能 | 更快且更轻量。 | 由于涉及递归操作,因此较慢。 |
使用场景 | 扁平的或嵌套较少的对象。 | 嵌套较深的对象或不可变的数据结构。 |
何时使用浅复制:
- 扁平化对象:当处理没有嵌套属性的简单对象时。
- 性能优化:当速度至关重要且不需要处理深层嵌套的数据时。
- 临时修改:当你打算修改顶级属性但共享嵌套数据时。
示例使用方法
复制用户的设置,以便快速调整:
const 用户设定 = { 主题: "深色", 布局: "网格布局" };
const 更新后的设定 = { ...用户设定, 布局: "列表布局" };
全屏 退出全屏
什么时候需要用到深复制
- 复杂结构:对于有多层嵌套结构的对象。
- 避免副作用:当你需要确保副本的修改不会影响到原对象时。
- 状态管理:在像 React 或 Redux 这样的框架中,保持不可变性至关重要。
示例用法
复制游戏或应用的状态:
const gameState = {
level: 5,
inventory: {
weapons: ["剑", "盾"],
potions: 3
}
};
// 这样做可以避免产生副作用
const savedState = JSON.parse(JSON.stringify(gameState));
进入全屏 关闭全屏
常见的错误和坑
- 假设浅复制总是足够的话:
-
开发者常常错误地使用浅拷贝方法来处理嵌套对象时,导致原始数据意外被修改。
- 过度依赖 JSON 方法:
-
虽然
JSON.stringify
和JSON.parse
很简单,但它们并不适用于所有对象(例如,包含方法或存在循环引用的对象)。- 忽略性能,
-
深拷贝可能更慢,特别是对于大对象,所以请酌情使用。
-
- *
结论
理解浅拷贝和深拷贝之间的区别对于编写无bug的JavaScript代码来说至关重要。浅拷贝对于简单的结构很高效,而深拷贝对于复杂的、嵌套的对象则是必不可少的。根据你的需求选择合适的方法,并通过了解每种方法的限制来避免潜在的问题。
共同学习,写下你的评论
评论加载中...
作者其他优质文章