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

阅读时长 7 分钟读完

在 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

纠错
反馈