通过 ES8 中的对象函数,解决 JavaScript 对象深复制问题

在 JavaScript 开发中,对象复制是一个常见的操作。很多开发者都会遇到一种情况:只复制了对象的浅层属性而没有复制其深层属性。在 ES8 中,有一些对象函数可以帮助我们完成对象深复制的操作,本文将会介绍这些函数。

浅复制和深复制

在介绍深复制过程中,先来回顾一下什么是浅复制。所谓浅复制,就是只复制对象的一层属性,而不复制对象里面的子对象。比如:

--- ---- - ------ -------- ------ ----------- ----------
--- ---- - ----------------- ------

------------------
-- ------ -------- ------ ---------

--------------------------

------------------
-- ------ -------- ------ ---------
------------------
-- ------ -------- ------ ---------

在上面的例子中,我们使用了 Object.assign() 函数来进行对象的浅复制。虽然 obj2obj1 看起来内容一样,但其实 obj2 中的 hobby 数组只是一个指向 obj1 中该数组的指针,它们是同一个数组对象。所以当我们修改 obj2 中的 hobby 数组的值时,实际上也修改了 obj1 中的 hobby 数组的值。

相对于浅复制,深复制则是对对象和其所有子对象进行复制,使复制品与原版互不影响。比如:

--- ---- - ------ -------- ------ ----------- ----------
--- ---- - ---------------------------------

------------------
-- ------ -------- ------ ---------

--------------------------

------------------
-- ------ -------- ------ ---------
------------------
-- ------ -------- ------ ---------

在上面的例子中,我们使用了 JSON.stringify()JSON.parse() 函数来进行对象的深复制。虽然这种方法可以深复制对象,但它不支持复制函数,而且会忽略对象中的非枚举属性。

ES8 中的对象函数

在 ES8 中,新增了一些对象函数可以辅助我们完成对象的深复制。其中,最常用的函数是 Object.assign()Object.getOwnPropertyDescriptors()Object.create()

Object.assign()

在前面的例子中,我们已经介绍了 Object.assign() 函数可以用于对象的浅复制。但实际上,它也可以用于对象的深复制。比如:

--- ---- - ------ -------- ------ ----------- ----------
--- ---- - ----------------- ----- ------- ------------------

------------------
-- ------ -------- ------ ---------

--------------------------

------------------
-- ------ -------- ------ ---------
------------------
-- ------ -------- ------ ---------

在上面的例子中,我们使用了 [...obj1.hobby] 来复制 obj1 中的 hobby 数组,从而实现了对象的深复制。

不过,当复制的对象中存在子对象时,Object.assign() 仍然只能进行浅复制。比如:

--- ---- - ------ -------- -------- ------ ---------- -------- ----------
--- ---- - ----------------- ------

------------------
-- ------ -------- -------- ----

----------------- - -----------

------------------
-- ------ -------- -------- ------ ----------- -------- ---------
------------------
-- ------ -------- -------- ------ ----------- -------- ---------

在上面的例子中,我们复制了 obj1 对象,但是由于 obj1 中的 address 属性是一个对象,所以复制后的 obj2 中也只是将 address 属性复制了一份引用,没有真正完成深复制,因此在修改 obj2 中的 address.city 属性时,obj1 中的 address.city 属性也被修改了。

Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors() 函数可以获取指定对象的所有自身属性的描述符,包括 configurable、enumerable、writable 和 value 属性。利用这个函数,我们可以精确地对对象进行深复制。比如:

--- ---- - ------ -------- -------- ------ ---------- -------- ----------
--- ---- - ---

----------------------------- ----------------------------------------

------------------
-- ------ -------- -------- ----

----------------- - -----------

------------------
-- ------ -------- -------- ------ ---------- -------- ---------
------------------
-- ------ -------- -------- ------ ----------- -------- ---------

在上面的例子中,我们使用了 Object.defineProperties() 函数定义了 obj2 的属性以及它们的描述符,这些描述符是通过 Object.getOwnPropertyDescriptors() 函数从 obj1 获取的。这样,复制过程中便包含了它们的配置信息,也就实现了完整的深复制。

Object.create()

Object.create() 函数可以创建一个新对象,该对象的原型继承自指定的原型对象,并拥有指定的属性。通过这个函数,可以实现对象的深复制。比如:

--- ---- - ------ -------- -------- ------ ---------- -------- ----------
--- ---- - ------------------------------------------ ----------------------------------------

------------------
-- ------ -------- -------- ----

----------------- - -----------

------------------
-- ------ -------- -------- ------ ---------- -------- ---------
------------------
-- ------ -------- -------- ------ ----------- -------- ---------

在上面的例子中,我们使用了 Object.getPrototypeOf() 函数获取了 obj1 的原型对象,并将其传递给了 Object.create() 函数,从而创建了一个新对象,该对象的原型继承自 obj1 的原型对象。然后,我们又使用了 Object.getOwnPropertyDescriptors() 函数获取了 obj1 的所有描述符,并将其传递给了 Object.create() 函数,从而创建了一个新对象,该对象拥有了 obj1 的所有属性,从而实现了深复制。

总结

通过上述分析,我们可以看到,ES8 中的三个对象函数都可以用于实现对象的深复制,而每个函数都有其优点和不足。如果对象只有单层属性,则可以使用 Object.assign() 函数进行深复制;如果对象包含嵌套的子对象,则可以使用 Object.defineProperties() 函数进行深复制;如果需要深复制对象的所有属性,包括继承自原型对象的属性,则可以使用 Object.create() 函数进行深复制。当我们在实际开发中需要对对象进行深复制时,可以根据实际情况选择合适的函数来使用。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/647eddfa48841e9894e8ae95


猜你喜欢

  • Material Design 中 TabLayout 自定义样式的实现方法

    Material Design 是 Google 推出的一种基于扁平化设计的 UI 设计风格,旨在为用户提供优美、简洁、统一的视觉体验。在 Material Design 中,TabLayout 是一...

    1 年前
  • 在 Tailwind CSS 中使用别名解决长 class 名不便读写问题

    Tailwind CSS 是一个流行的 CSS 框架,旨在提供大量可重用的类名和样式,以帮助开发人员更轻松地构建现代网站和应用程序。然而,这些类名通常很长,不易于记忆,并且可能难以阅读和编写。

    1 年前
  • Mongoose 如何优雅的处理数据的历史版本?

    在开发 Web 应用程序时,数据版本管理是一个非常常见的需求。开发者常常需要记录一个文档或实体的修改历史,或者跟踪一个具体时间点的状态。Mongoose 是一个流行的 Node.js 对象文档映射器(...

    1 年前
  • Redis 使用中遇到的内存问题解决技巧

    前言 Redis 是一款高性能的键值存储数据库,被广泛用于缓存、消息队列、统计分析等场景。Redis 采用内存存储机制,能够实现高速读写,并提供了丰富的数据结构和操作命令,具有很好的扩展性和灵活性。

    1 年前
  • 动手实践:使用 CSS Reset 解决浏览器默认样式问题

    动手实践:使用 CSS Reset 解决浏览器默认样式问题 在前端开发中,我们常常会遇到浏览器默认样式的问题。比如,不同浏览器对于相同元素的默认样式可能有所不同,导致我们无法实现相同的样式效果。

    1 年前
  • Socket.io 断连后自动重连实现方式

    Socket.io 是一个用于实时通信的 JavaScript 库,它提供了轻松快速的双向通信,支持多种传输协议,可以实现客户端和服务器之间的实时数据传输和通信。 然而,在使用 Socket.io 进...

    1 年前
  • MongoDB 的性能瓶颈分析及优化方法探究

    一、概述 MongoDB 是一款流行的 NoSQL 数据库,以其高可靠、高扩展性和易用性著称。但是,与其它数据库一样,MongoDB 也会有性能瓶颈问题。本文将深入探究 MongoDB 的性能瓶颈问题...

    1 年前
  • Performance Optimization:解决网站首页加载缓慢的问题

    在现代互联网时代,一个高效快速的网站对于用户体验与流量增长至关重要。然而,在实际开发中,很多网站在首页加载时会遇到缓慢的问题,导致用户体验严重下降,甚至可能失去潜在流量。

    1 年前
  • 使用 Custom Elements 构建可组合的 UI 设计系统

    在前端开发中,我们经常需要构建各种 UI 组件来实现界面的呈现以及页面的交互处理。如果我们用传统的方式编写组件,通常会让代码变得混乱不堪,维护成本也会越来越高。为了解决这个问题,我们可以使用 Cust...

    1 年前
  • TypeScript 中闭包函数使用的注意事项及解决方式

    在 TypeScript 中,闭包函数是一种重要的编程方式。它可以用来实现许多复杂的逻辑,但是在使用过程中也存在一些常见的问题和注意事项。本文将介绍 TypeScript 中闭包函数的使用方法,解决常...

    1 年前
  • 提速 Hapi 应用程序 – 单元测试

    在开发 Hapi 应用程序时,单元测试是不可避免的一环。通过单元测试,我们可以确保代码的质量和程序的稳定性,同时也能够加快开发效率和降低错误率。在本文中,我们将探讨如何通过单元测试来提速 Hapi 应...

    1 年前
  • 从 ES6 到 ES10,你需要了解的 JavaScript 新特性

    前言 作为现代 Web 开发中不可或缺的一部分,JavaScript 一直在不断发展和改进。每一年 ECMAScript 都会发布新版本,增加新功能和语言特性。而自 2015 年发布了 ECMAScr...

    1 年前
  • Express.js 回调函数正在等待

    回调函数是一种用于异步编程的常见技术。在 Node.js 中,回调函数可以将请求发送到服务器并处理响应。对于 web 开发人员来说,使用回调函数来处理输入或输出很常见,尤其是在使用 Express.j...

    1 年前
  • 使用 Flexbox 实现固定表格布局

    前言 固定表格布局是在前端开发中经常遇到的需求,不管是产品列表、数据报表,还是电商订单列表等,都需要将数据以表格的形式呈现出来。这时候,我们不仅要考虑表格数据的内容、样式,还需要考虑表格布局的问题。

    1 年前
  • 学习 Kubernetes,必须要了解的几个概念

    随着微服务架构的流行,Kubernetes成为了容器编排领域的一颗重要明星。Kubernetes可以帮助开发者更好的管理和运行容器化应用。学习Kubernetes,需要掌握许多概念,本文将为大家详细解...

    1 年前
  • 如何使用 Docker 部署 Java 应用程序?

    什么是 Docker? Docker 是一种用于开发、部署和运行应用程序的开源容器化平台。通过使用 Docker,开发者可以快速地部署应用程序、确保程序在不同环境下的一致性,并加快应用程序的开发和部署...

    1 年前
  • Webpack 构建性能优化之 Babel

    随着前端技术的不断发展,前端的开发工具也越来越多,Webpack 作为一个前端构建工具,广受开发者的欢迎。然而,在大规模的项目中,Webpack 构建的性能问题是不可避免的。

    1 年前
  • 详解 Sequelize 中的 Hooks

    Sequelize 是一个 Node.js 的 ORM 框架,用于操作 SQL 数据库,提供了丰富的 API 和功能,同时也支持使用 Hooks 来拦截和处理数据库操作事件。

    1 年前
  • JavaScript 异步优化新思路:ES7 中引入的 async function

    在前端开发中,处理异步逻辑一直是一个比较棘手的问题。传统的回调函数方式使得代码可读性差、可维护性低,而 Promise 也存在过度嵌套等问题。而在 ES7 中,我们可以使用 async functio...

    1 年前
  • 集成 Babel 到你的应用开发工作流程中

    前端开发离不开 JavaScript,但是现代的 JavaScript 规范更新非常快,而不同的浏览器又对规范的支持程度千差万别,这就导致了我们在编写 JavaScript 代码的时候需要考虑非常多的...

    1 年前

相关推荐

    暂无文章