Object.assign 可以实现对象的合并。它的语法是这样的: Object.assign(target, ...sources)
,
Object.assign
会将 source 里面的可枚举属性复制到 target
。
开发中,很多人对 Object.assign 的用法不清,很容易导致以下 2 种情况,使得源对象属性改变
# 问题一:覆盖同名属性,导致源对象属性改变
如果和 target 的已有属性重名,则会覆盖。同时后续的 source 会覆盖前面的 source 的同名属性。
举例说明:
const o1 = { name: 'aa', status: true, num: 11 } | |
const o2 = { name: 'bb', status: false, num: 22 } | |
const o3 = Object.assign(o1, o2) // 错误写法 | |
// o3 { name: 'bb', status: false, num: 22 } | |
// o1 { name: 'bb', status: false, num: 22 } | |
// o2 { name: 'bb', status: false, num: 22 } | |
o3.topic.push('css') | |
// 正确写法 const o3 = Object.assign ({}, o1, o2) | |
// o3 { name: 'bb', status: false, num: 22 } | |
// o1 { name: 'aa', status: true, num: 11 } | |
// o2 { name: 'bb', status: false, num: 22 } |
PS: 如果一定要这么写,请用 JSON.parse 包裹,即: const o3 = Object.assign(JSON.parse(JSON.stringify(o1)), o2)
# 问题二:修改引用属性,导致源对象属性改变
⚠️Object.assign 复制的是属性值,如果属性值是一个引用类型,那么复制的其实是引用地址,就会存在引用共享的问题。
举例说明:
const o1 = { name: 'fedaily' } | |
const o2 = { topic: ['react', 'nodejs'] } | |
const o3 = Object.assign({}, o1, o2) | |
// o3 { name: 'fedaily', topic: ['react', 'nodejs'] } | |
o3.topic.push('css') | |
// o3 { name: 'fedaily', topic: ['react', 'nodejs', 'css'] } | |
// o2 { topic: ['react', 'nodejs', 'css'] } | |
// ⚠️我们可以看到所有对象的 topic 值都被更新了 |
所以,当我们快乐的想要使用 Object.assign 的时候,需要特殊关注一下是否有引用类型。
如果我们需要处理引用类型怎么办呢,这就涉及到对象的拷贝了,可以参考 lodash 的_clone, _cloneDeep 等方法。
再附上 MDN 关于 Object.assign 的 polyfill,方便大家理解内部实现,同时更好的掌握这个方法哟
if (typeof Object.assign != 'function') { | |
Object.assign = function (target, varArgs) { // .length of function is 2 | |
'use strict'; | |
if (target == null) { // TypeError if undefined or null | |
throw new TypeError('Cannot convert undefined or null to object'); | |
} | |
var to = Object(target); | |
for (var index = 1; index < arguments.length; index++) { | |
var nextSource = arguments[index]; | |
if (nextSource != null) { // Skip over if undefined or null | |
for (var nextKey in nextSource) { | |
// Avoid bugs when hasOwnProperty is shadowed | |
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { | |
to[nextKey] = nextSource[nextKey]; | |
} | |
} | |
} | |
} | |
return to; | |
}; | |
} |