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

大家好,这里是大家的林语冰 。
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()) 应该游刃有余 , 但有时我们可能想使用 


推荐阅读