在前端开发中,经常需要对对象进行拷贝与合并。ECMAScript 2019中的Object.assign方法为我们提供了方便的对象拷贝与合并操作。在本文中,我们将深入探讨Object.assign的用法,并讨论对象的深浅拷贝问题。
了解Object.assign
Object.assign 方法用于将所有可枚举的属性,从一个或多个源对象复制到目标对象。该方法返回目标对象。示例代码如下:
const target = {a: 1, b: 2}; const source = {b: 3, c: 4}; Object.assign(target, source); console.log(target); // {a: 1, b: 3, c: 4}
上述示例中,我们将source对象中的b、c属性拷贝到了target对象中。需要注意的是,如果target对象中有与source对象同名的属性,则会覆盖掉原来的值。
除了基本类型的值属性外,Object.assign也可以拷贝引用类型的属性,如数组或对象。示例如下:
const target = {a: 1, b: {c: 2}}; const source = {b: {d: 3}}; Object.assign(target, source); console.log(target); // {a: 1, b: {d: 3}}
注意,该示例中,source对象的属性b也是一个对象,它和target对象的属性b指向的是同一个引用。因此,通过Object.assign拷贝属性b时,拷贝的是b引用的地址,而不是复制一个新的对象。
深拷贝与浅拷贝
在前面的例子中,我们演示了基本类型的属性值与引用类型的属性值的拷贝。但仅仅使用Object.assign仅仅是浅拷贝,也就是说只拷贝了引用,而没有拷贝引用指向的对象的内容。如果我们需要深拷贝一个对象,则需要借助其他的方法。
手写深拷贝函数
手写深拷贝函数的思路是,使用递归的方式遍历待拷贝的对象,当发现属性的值是引用类型时,再次调用深拷贝函数递归拷贝子对象。示例代码如下:
-- -------------------- ---- ------- -------- ------------- - -- ---- --- ---- -- ------ --- --- --------- - ------ ---- - ----- --------- - ------------------ - -- - --- --- ---- --- -- ---- - -- ------------------------------------------ ----- - -------------- - ------------------- - - ------ ---------- -
这里需要注意两个问题:
判断obj是否为对象或数组时,需要特判null,因为null的typeof值也是object。
在遍历对象属性时,需要通过Object.prototype.hasOwnProperty.call(obj, key)来判断该属性是否是对象自身的属性,而不是从原型继承而来的属性。
借助第三方库
如果你不想为了深拷贝而手写一个函数,也可以考虑使用一些第三方库来完成这个任务。例如,lodash中的_.cloneDeep方法可以帮助我们完成对象的深拷贝操作。示例代码如下:
const _ = require('lodash'); const obj1 = {a: 1, b: {c: 2}}; const obj2 = _.cloneDeep(obj1); console.log(obj2); // {a: 1, b: {c: 2}}
需要注意的是,在使用这些库时,需要小心避免出现安全问题。因为对于拷贝一些特别大的、复杂的对象时,这些拷贝操作可能会耗费大量的CPU和内存资源,甚至会导致服务崩溃。
总结
在ECMAScript 2019中,我们可以使用Object.assign方法来拷贝对象属性。但是由于该方法只是浅拷贝,需要特别注意对象属性值为引用类型的情况。在拷贝引用类型的属性时,需要使用深拷贝。深拷贝可以手写一个函数实现,也可以使用第三方库。在实际的开发中,需要谨慎使用这些方法,防止出现性能和安全问题。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64a158ef48841e9894d9e669