JS中如何克隆对象(深克隆浅克隆递归克隆)

 更新时间:2024年01月21日 15:49:51   作者:大家的林语冰 人猫神话  
这篇文章主要介绍了JS中如何克隆对象(深克隆浅克隆递归克隆)的全面探索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

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 函数来拷贝复杂的对象。在选择克隆机制之前,请了解您的数据。

How to clone an object in JavaScript?: https://www.strictmode.io/articles/clone 

以上就是JS中如何克隆对象(深克隆浅克隆递归克隆)的详细内容,更多关于JS克隆对象的资料请关注脚本之家其它相关文章!

相关文章

  • 详解微信小程序动画Animation执行过程

    详解微信小程序动画Animation执行过程

    这篇文章主要介绍了微信小程序动画Animation执行过程 / 实现过程 / 实现方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • 输入密码检测大写是否锁定js实现代码

    输入密码检测大写是否锁定js实现代码

    网站登录为了更好的用户体验都会在输入密码的时候检测是否开启大写,这样有助于提醒用户,需要学习的朋友可以参考下
    2012-12-12
  • JS滚动到指定位置导航栏固定顶部

    JS滚动到指定位置导航栏固定顶部

    最近整理一下之前做的一个项目,把滚动条动态固定顶部的代码整理出来和大家分享
    2017-07-07
  • js简单的表拖拽

    js简单的表拖拽

    用js实现表格的拖拽效果代码
    2008-05-05
  • js中获取URL参数的共用方法getRequest()方法实例详解

    js中获取URL参数的共用方法getRequest()方法实例详解

    本文通过实例代码给大家介绍了js中获取URL参数的共用方法getRequest()方法 ,文末给大家提到了js获取url参数值的两种方式,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-10-10
  • 详述 Sublime Text 打开 GBK 格式中文乱码的解决方法

    详述 Sublime Text 打开 GBK 格式中文乱码的解决方法

    这篇文章主要介绍了详述 Sublime Text 打开 GBK 格式中文乱码的解决方法,非常具有实用价值,需要的朋友可以参考下
    2017-10-10
  • 微信小程序调用摄像头隐藏式拍照功能

    微信小程序调用摄像头隐藏式拍照功能

    这篇文章主要介绍了微信小程序调用摄像头隐藏式拍照功能,本文给大家带来了解决方法、官网代码和小编写的比较完整代码,需要的朋友可以参考下
    2018-08-08
  • javaScript 关闭浏览器 (不弹出提示框)

    javaScript 关闭浏览器 (不弹出提示框)

    如果网页不是通过脚本程序打开的(window.open()),调用window.close()脚本关闭窗口前,必须先将window.opener对象置为null,否则浏览器(IE7、IE8)会弹出一个确定关闭的对话框。
    2010-01-01
  • TypeScript中的类

    TypeScript中的类

    这篇文章主要介绍了TypeScript中的类,类这个概念基本是所有面向对象编程语言都具有一个概念,JavaScript中ES6 之前是没有类这个概念,下面文章围绕TypeScript类的相关资料展开内容,需要的朋友可以参考一下
    2021-12-12
  • 基于js中的存储键值对以及注意事项介绍

    基于js中的存储键值对以及注意事项介绍

    下面小编就为大家介绍一下基于js中的存储键值对以及注意事项。希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03

最新评论