在 ES6 中,可以使用 Object.assign()
方法将多个对象的属性合并到一个新对象中。但是在使用该方法时,会遇到几个问题。本文将分析这些问题并提供解决方案。本文内容详细,适合前端开发人员学习和实践。
问题一:浅拷贝
Object.assign()
方法执行的是浅拷贝,即只拷贝对象的一层属性。当对象的属性也是对象时,拷贝的是对象的引用,而非对象本身。如下所示:
let obj1 = {person: {name: '张三', age: 18}}; let obj2 = Object.assign({}, obj1); obj2.person.name = '李四'; console.log(obj1.person.name); // 李四
上述代码中,我们将 obj1
的属性拷贝到 obj2
中,然后修改了 obj2
中的 person
对象的 name
属性。但是,修改后发现 obj1
的 person
对象的 name
属性也被一起修改了。这是因为 obj2
中的 person
对象和 obj1
中的 person
对象是同一个对象。
解决方案
为了避免这个问题,我们需要使用深拷贝代替浅拷贝。可以使用 JSON.parse(JSON.stringify(obj))
来进行深拷贝。
let obj1 = {person: {name: '张三', age: 18}}; let obj2 = JSON.parse(JSON.stringify(obj1)); obj2.person.name = '李四'; console.log(obj1.person.name); // 张三
这样,就可以成功地修改 obj2
中的 person
对象的 name
属性,而不会改变 obj1
中的 person
对象。
但是,该解决方案也有缺陷。当对象中的属性是函数、日期等特殊类型时,JSON.stringify()
会将其转为字符串,从而导致深拷贝失效。
更好的解决方案
更好的解决方案是使用第三方库 lodash
中的 cloneDeep()
方法。该方法可以对任意深度的对象进行深拷贝。
import cloneDeep from 'lodash/cloneDeep'; let obj1 = {person: {name: '张三', age: 18}}; let obj2 = cloneDeep(obj1); obj2.person.name = '李四'; console.log(obj1.person.name); // 张三
问题二:只能复制可枚举属性
Object.assign()
方法只会复制对象的可枚举属性,而不会复制对象的不可枚举属性。例如,以下代码中的 toString()
方法就是不可枚举属性。
-- -------------------- ---- ------- --- ---- - - ----- ----- ---- --- --------- ---------- - ------ ------ - - --------- - -- ---- - - --------- - -- --- ---- - ----------------- ------ ----------------------------- -- ------- -------
上述代码中,我们将 obj1
的属性拷贝到 obj2
中,然后尝试调用 obj2
的 toString()
方法。但是,调用结果并非我们期望的 name: 张三, age: 18
,而是 [object Object]
。
解决方案
为了复制对象的所有属性,包括不可枚举属性,可以使用 Object.getOwnPropertyNames()
方法和 Object.getOwnPropertySymbols()
方法获取所有属性名和符号,并使用 Object.defineProperties()
方法将属性复制到新对象中。
-- -------------------- ---- ------- --- ---- - - ----- ----- ---- --- --------------- ------ --------- ---------- - ------ ------ - - --------- - -- ---- - - --------- - -- --- ---- - --- ------------------------------------------------------ - --------- - ---------- --- -------------------------------------------------------- - --------- - ---------- --- ----------------------------- -- ----- --- ---- -- -------------------------------- -- ---
上述代码中,我们使用 Object.getOwnPropertyNames()
方法和 Object.getOwnPropertySymbols()
方法获取了 obj1
的所有属性名和符号,并使用 forEach()
方法循环将这些属性复制到 obj2
中。这样,就可以成功地复制对象的所有属性,包括不可枚举属性。
总结
在使用 Object.assign()
方法时,需要注意浅拷贝和只能复制可枚举属性等问题。我们可以使用 JSON.parse(JSON.stringify(obj))
进行深拷贝,或使用 lodash
中的 cloneDeep()
方法。如果需要复制对象的所有属性,包括不可枚举属性,则可以使用 Object.getOwnPropertyNames()
方法和 Object.getOwnPropertySymbols()
方法获取所有属性名和符号,并使用 Object.defineProperties()
方法将属性复制到新对象中。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64a22f7b48841e9894e798d8