您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > javascript

JS 中如何克隆对象?你学会了吗?

时间:2024-01-05 14:18:16  来源:微信公众号  作者:人猫神话

大家好,这里是大家的林语冰。

JS 中如何克隆对象?此问题看似简单,实际十分复杂。

假设我们需要获取下述对象的拷贝。

const cat = {
  name: '薛定谔',
  girlFriends: { name: '龙猫' }
}

我们应该简单地创建一个新变量吗?(不)

如果我们将对象赋值给一个新变量,那几乎毫无卵用。

const newCar = cat
newCat.name = '柴郡猫'

console.log(newCat.name) //=> 柴郡猫
console.log(cat.name) //=> 柴郡猫

两个对象都会变化。

原因很简单 —— 我们并没有创建一个新对象。我们只是创建了一个新的引用。

现在有两个变量:cat 和 newCat,它们都引用同一个对象。

浅克隆

何时浅克隆:当我们的对象属性有且仅有一层深度,或者我们不关心嵌套引用时。

当且仅当源对象不包含对其他对象的任何引用时,浅克隆才有效。

const newCat = { ...cat }

newCar.name = '柴郡猫'
console.log(newCat.name) //=> 柴郡猫
console.log(cat.name) //=> 薛定谔

newCat.girlFriends.name = '加菲猫'
console.log(newCat.girlFriends.name) //=> 加菲猫
console.log(cat.girlFriends.name) //=> 加菲猫

更新女友名字也会导致原始名字变化,这是因为 newCat.girlFriends 和 car.girlFriends 仍然引用内存中的同一对象。

这就是为什么它被称为“浅”克隆:它能且仅能拷贝顶层属性。

在我们的示例中,我们使用展开运算符 ... 来执行浅克隆,但我们也可以使用 Object.assign

const newCat = Object.assign({}, cat)

通过 JSON 深克隆

何时使用此方案:当且仅当我们需要深克隆,且我们的对象有且仅有数组、原始值和其他普通对象时。

克隆对象的一种流行方案是,将其转换为 JSON 字符串,然后解析它。

const newCat = JSON.parse(JSON.stringify(cat))

newCat.name = '柴郡猫'
console.log(newCat.name) //=> 柴郡猫
console.log(cat.name) //=> 薛定谔

newCat.girlFriends.name = '加菲猫'
console.log(newCat.girlFriends.name) //=> 加菲猫
console.log(cat.girlFriends.name) //=> 龙猫

虽然此方案适用于大多数情况,但它仍然有其局限性。它能且仅能转换普通对象。

// Date 对象会变成字符串
JSON.parse(JSON.stringify({ now: new Date() }))
// {now: '2022-07-14T13:21:36.761Z'}

// undefined 对应属性人间蒸发
JSON.parse(JSON.stringify({ girlFriends: undefined }))
//=> {}

// 无法克隆 Set
JSON.parse(JSON.stringify({ set: new Set([9]) }))
//=> { set: {} }

// 无法克隆 Symbol
JSON.parse(JSON.stringify({ symbol: Symbol('996') }))
//=> {}

// 无法克隆正则
JSON.parse(JSON.stringify({ regex: /996/i }))
//=> {}

// 无法克隆 BigInt
JSON.parse(JSON.stringify({ bigint: 996n }))
//=> 未捕获类型错误:无法序列化 BigInt

递归克隆

何时使用此方案:当且仅当我们的对象包含复杂的结构(比如 Map/RegExp 等)时。

structuredClone 可以搞定大部分问题。

如你所愿,它通过递归遍历对象来工作。它足够机智,可以使用循环引用拷贝对象,并且知道如何克隆不同类型的数据(包括但不限于 Map/Set/Date 等)。

structuredClone({ regex: /996/i, set: new Set([9]) })
//=> { regex: /996/i, set: Set(1) {9}}

它仍然有其局限性:举个栗子,它无法克隆函数或 DOM 节点。

令人鸡冻的是,它已经被所有主流浏览器支持。

粉丝请注意,它不是 ECMAScript 标准的一部分,而是浏览器 API 的一部分,并且不同浏览器的实现可能一龙一猪。Node 根本没有此 API。

或者,我们始终可以使用 lodash 的 cloneDeep,它实现了类似的算法。

完结撒花

根据情况选择特定的克隆机制。虽然我相信,在大多数情况下,JSON.parse(JSON.stringify()) 应该游刃有余,但有时我们可能想使用 structuredClone 函数来拷贝复杂的对象。在选择克隆机制之前,请了解您的数据。



Tags:JS   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
又出新JS运行时了!JS运行时大盘点
Node.js是基于Google V8引擎的JavaScript运行时,以非阻塞I/O和事件驱动架构为特色,实现全栈开发。它跨平台且拥有丰富的生态系统,但也面临安全性、TypeScript支持和性能等挑战...【详细内容】
2024-03-21  Search: JS  点击:(22)  评论:(0)  加入收藏
GitHub顶流"Web OS"——运行于浏览器的桌面操作系统、用户超100万、原生jQuery和JS编写
Puter 是近日在 GitHub 上最受欢迎的一款开源项目,正式开源还没到一周 ——star 数就已接近 7k。作者表示这个项目已开发 3 年,并获得了超过 100 万用户。根据介绍,P...【详细内容】
2024-03-10  Search: JS  点击:(17)  评论:(0)  加入收藏
前端开始“锈化”?Vue团队开源JS打包工具:基于Rust、速度极快、尤雨溪主导
Vue 团队已正式开源Rolldown —— 基于 Rust 的 JavaScrip 打包工具。Rolldown 是使用 Rust 开发的 Rollup 替代品,它提供与 Rollup 兼容的应用程序接口和插件接口...【详细内容】
2024-03-09  Search: JS  点击:(11)  评论:(0)  加入收藏
如何在Rust中操作JSON,你学会了吗?
sonic-rs ​还具有一些额外的方法来进行惰性评估和提高速度。例如,如果我们想要一个 JSON​ 字符串文字,我们可以在反序列化时使用 LazyValue​ 类型将其转换为一个仍然带有斜...【详细内容】
2024-02-27  Search: JS  点击:(47)  评论:(0)  加入收藏
JS小知识,使用这6个小技巧,避免过多的使用 if 语句
最近在重构我的代码时,我注意到早期的代码使用了太多的 if 语句,达到了我以前从未见过的程度。这就是为什么我认为分享这些可以帮助我们避免使用过多 if 语句的简单技巧很重要...【详细内容】
2024-01-30  Search: JS  点击:(56)  评论:(0)  加入收藏
花 15 分钟把 Express.js 搞明白,全栈没有那么难
Express 是老牌的 Node.js 框架,以简单和轻量著称,几行代码就可以启动一个 HTTP 服务器。市面上主流的 Node.js 框架,如 Egg.js、Nest.js 等都与 Express 息息相关。Express 框...【详细内容】
2024-01-16  Search: JS  点击:(85)  评论:(0)  加入收藏
JS 中如何克隆对象?你学会了吗?
大家好,这里是大家的林语冰。JS 中如何克隆对象?此问题看似简单,实际十分复杂。假设我们需要获取下述对象的拷贝。const cat = { name: '薛定谔', girlFriends: { na...【详细内容】
2024-01-05  Search: JS  点击:(102)  评论:(0)  加入收藏
理解 Node.js 中的事件循环
你已经使用 Node.js 一段时间了,构建了一些应用程序,尝试了不同的模块,甚至对异步编程感到很舒适。但是有些事情一直在困扰着你——事件循环(Event Loop)。如果你像我...【详细内容】
2024-01-05  Search: JS  点击:(110)  评论:(0)  加入收藏
彻底搞懂 JS 类型转换
1. 什么是类型转换?Javascript 是一种弱类型语言,这意味着变量是没有明确类型的,而是由 JavaScript 引擎在编译时隐式完成。类型转换就是将一种数据类型转换为另一种数据类型,例...【详细内容】
2024-01-03  Search: JS  点击:(103)  评论:(0)  加入收藏
.NET配置文件大揭秘:轻松读取JSON、XML、INI和环境变量
概述:.NET中的IConfiguration接口提供了一种多源读取配置信息的灵活机制,包括JSON、XML、INI文件和环境变量。通过示例,清晰演示了从这些不同源中读取配置的方法,使配置获取变得...【详细内容】
2023-12-28  Search: JS  点击:(92)  评论:(0)  加入收藏
▌简易百科推荐
17 个你需要知道的 JavaScript 优化技巧
你可能一直在使用JavaScript搞开发,但很多时候你可能对它提供的最新功能并不感冒,尽管这些功能在无需编写额外代码的情况下就可以解决你的问题。作为前端开发人员,我们必须了解...【详细内容】
2024-04-03  前端新世界  微信公众号  Tags:JavaScript   点击:(4)  评论:(0)  加入收藏
你不可不知的 15 个 JavaScript 小贴士
在掌握如何编写JavaScript代码之后,那么就进阶到实践——如何真正地解决问题。我们需要更改JS代码使其更简单、更易于阅读,因为这样的程序更易于团队成员之间紧密协...【详细内容】
2024-03-21  前端新世界  微信公众号  Tags:JavaScript   点击:(25)  评论:(0)  加入收藏
又出新JS运行时了!JS运行时大盘点
Node.js是基于Google V8引擎的JavaScript运行时,以非阻塞I/O和事件驱动架构为特色,实现全栈开发。它跨平台且拥有丰富的生态系统,但也面临安全性、TypeScript支持和性能等挑战...【详细内容】
2024-03-21  前端充电宝  微信公众号  Tags:JS   点击:(22)  评论:(0)  加入收藏
构建一个通用灵活的JavaScript插件系统?看完你也会!
在软件开发中,插件系统为应用程序提供了巨大的灵活性和可扩展性。它们允许开发者在不修改核心代码的情况下扩展和定制应用程序的功能。本文将详细介绍如何构建一个灵活的Java...【详细内容】
2024-03-20  前端历险记  微信公众号  Tags:JavaScript   点击:(20)  评论:(0)  加入收藏
对JavaScript代码压缩有什么好处?
对JavaScript代码进行压缩主要带来以下好处: 减小文件大小:通过移除代码中的空白符、换行符、注释,以及缩短变量名等方式,可以显著减小JavaScript文件的大小。这有助于减少网页...【详细内容】
2024-03-13  WangLiwen    Tags:JavaScript   点击:(2)  评论:(0)  加入收藏
跨端轻量JavaScript引擎的实现与探索
一、JavaScript 1.JavaScript语言JavaScript是ECMAScript的实现,由ECMA 39(欧洲计算机制造商协会39号技术委员会)负责制定ECMAScript标准。ECMAScript发展史: 2.JavaScript...【详细内容】
2024-03-12  京东云开发者    Tags:JavaScript   点击:(2)  评论:(0)  加入收藏
面向AI工程的五大JavaScript工具
令许多人惊讶的是,一向在Web开发领域中大放异彩的JavaScript在开发使用大语言模型(LLM)的应用程序方面同样大有价值。我们在本文中将介绍面向AI工程的五大工具,并为希望将LLM...【详细内容】
2024-02-06    51CTO  Tags:JavaScript   点击:(52)  评论:(0)  加入收藏
JS小知识,使用这6个小技巧,避免过多的使用 if 语句
最近在重构我的代码时,我注意到早期的代码使用了太多的 if 语句,达到了我以前从未见过的程度。这就是为什么我认为分享这些可以帮助我们避免使用过多 if 语句的简单技巧很重要...【详细内容】
2024-01-30  前端达人  今日头条  Tags:JS   点击:(56)  评论:(0)  加入收藏
18个JavaScript技巧:编写简洁高效的代码
本文翻译自 18 JavaScript Tips : You Should Know for Clean and Efficient Code,作者:Shefali, 略有删改。在这篇文章中,我将分享18个JavaScript技巧,以及一些你应该知道的示例...【详细内容】
2024-01-30  南城大前端  微信公众号  Tags:JavaScript   点击:(65)  评论:(0)  加入收藏
使用 JavaScript 清理我的 200GB iCloud,有了一个意外发现!
本文作者在综合成本因素之下,决定用 Java 脚本来清理一下自己的 iCloud,结果却有了一个意外发现,即在 iCloud 中上传同一个视频和删除此视频之后,iCloud 的空间并不一致,这到底是...【详细内容】
2024-01-11    CSDN  Tags:JavaScript   点击:(97)  评论:(0)  加入收藏
站内最新
站内热门
站内头条