大家好,这里是大家的林语冰 。
JS 中如何克隆对象?此问题看似简单,实际十分复杂 。
假设我们需要获取下述对象的拷贝 。
const cat = { name: '薛定谔', girlFriends: { name: '龙猫' }}
我们应该简单地创建一个新变量吗?(不)如果我们将对象赋值给一个新变量,那几乎毫无卵用 。
const newCar = catnewCat.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
字符串,然后解析它 。
【JS 中如何克隆对象?你学会了吗?】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 }))//=> {}// 无法克隆 SetJSON.parse(JSON.stringify({ set: new Set([9]) }))//=> { set: {} }// 无法克隆 SymbolJSON.parse(JSON.stringify({ symbol: Symbol('996') }))//=> {}// 无法克隆正则JSON.parse(JSON.stringify({ regex: /996/i }))//=> {}// 无法克隆 BigIntJSON.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())
应该游刃有余 , 但有时我们可能想使用
推荐阅读
- 理解 Node.js 中的事件循环
- 什么是布隆过滤器?如何实现布隆过滤器?
- 支付宝如何还款
- 荣耀V20手机如何控制海尔电视
- 在word中如何将文字倾斜,Ai要如何才可以将字体变成倾斜
- qq三国如何快速赚钱 qq三国如何快速赚钱
- 如何获取国家版“健康码”,我是商家怎么申请健康码让别人扫
- Word如何关闭自动保存功能
- 如何学会和女友的家人相处
- ps要如何才能复制选区,ps如何复制图层到别的工作区