JavaScript 对象合并方法详解及最佳实践
一、常用对象合并方法
1.1 展开运算符 (Spread Operator)
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const result = { ...obj1, ...obj2 };
// { a: 1, b: 3, c: 4 }
优点:
语法简洁直观
ES6+ 原生支持
创建新对象,不影响原对象
缺点:
浅拷贝(嵌套对象只复制引用)
无法合并复杂结构(如数组、特殊对象)
不支持深度合并
1.2 Object.assign()
const obj1 = { a: 1, b: { x: 1 } };
const obj2 = { b: { y: 2 }, c: 3 };
const result = Object.assign({}, obj1, obj2);
// { a: 1, b: { y: 2 }, c: 3 } // 注意:b.x 被覆盖
优点:
ES5+ 兼容性好
可合并多个对象
创建新对象(当第一个参数为{}时)
缺点:
浅拷贝
会覆盖同名属性
无法处理getter/setter
1.3 手动深度合并函数
function deepMerge(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
deepMerge(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return deepMerge(target, ...sources);
}
function isObject(item) {
return item && typeof item === 'object' && !Array.isArray(item);
}
const obj1 = { a: 1, b: { x: 1, y: 2 } };
const obj2 = { b: { y: 3, z: 4 }, c: 5 };
const result = deepMerge({}, obj1, obj2);
// { a: 1, b: { x: 1, y: 3, z: 4 }, c: 5 }
优点:
可深度合并
高度可定制
控制合并策略
缺点:
需要自己实现和维护
可能性能较低
需考虑循环引用
1.4 structuredClone() 方法
const obj1 = {
a: 1,
b: {
x: 1,
nested: { deep: 'value' }
},
c: [1, 2, 3],
date: new Date(),
map: new Map([['key', 'value']]),
set: new Set([1, 2, 3])
};
// 深度克隆
const cloned = structuredClone(obj1);
// 合并使用示例
const obj2 = { b: { y: 2 }, d: 4 };
const result = { ...structuredClone(obj1), ...obj2 };
// 或手动合并克隆后的对象
const merged = Object.assign(structuredClone(obj1), obj2);
优点:
真正的深度克隆(包括嵌套对象)
支持复杂类型:Date、Map、Set、ArrayBuffer等
官方标准,现代浏览器原生支持
处理循环引用
不共享任何引用
缺点:
不能克隆函数、DOM节点、Error对象等
性能开销较大(特别是大对象)
Node.js 17+ 和现代浏览器才支持
不能自定义合并策略
只能克隆,需要配合其他方法实现合并
1.5 Lodash 的 merge/mergeWith
// 需要安装 lodash
import { merge, mergeWith } from 'lodash';
const obj1 = { a: 1, b: { x: 1 } };
const obj2 = { b: { y: 2 }, c: 3 };
const result = merge({}, obj1, obj2);
// { a: 1, b: { x: 1, y: 2 }, c: 3 }
// 自定义合并逻辑
const customizer = (objValue, srcValue) => {
if (Array.isArray(objValue)) {
return objValue.concat(srcValue);
}
};
const result2 = mergeWith({}, obj1, obj2, customizer);
优点:
功能强大,深度合并
支持自定义合并逻辑
处理各种边缘情况
社区维护,稳定可靠
缺点:
增加包体积
需要引入外部库
1.6 JSON 方法(不推荐用于合并)
const obj1 = { a: 1, b: { x: 1 } };
const obj2 = { b: { y: 2 } };
const result = JSON.parse(JSON.stringify(obj1));
Object.assign(result, obj2);
// 注意:这种方式有局限性,不处理函数、循环引用等
优点:
简单暴力
创建完全独立的拷贝
缺点:
丢失函数、undefined、Symbol等
无法处理循环引用
性能较差
二、其他特殊场景方法
2.1 深度合并库:deepmerge
import deepmerge from 'deepmerge';
const obj1 = { a: 1, b: { x: 1 }, arr: [1, 2] };
const obj2 = { b: { y: 2 }, arr: [3, 4] };
// 默认合并
const result1 = deepmerge(obj1, obj2);
// { a: 1, b: { x: 1, y: 2 }, arr: [3, 4] }
// 数组合并策略
const result2 = deepmerge(obj1, obj2, {
arrayMerge: (target, source) => target.concat(source)
});
// { a: 1, b: { x: 1, y: 2 }, arr: [1, 2, 3, 4] }
2.2 使用 Proxy 实现响应式合并
function reactiveMerge(target, source) {
return new Proxy({...target, ...source}, {
set(obj, prop, value) {
console.log(`Property ${prop} changed to ${value}`);
obj[prop] = value;
return true;
}
});
}
三、方法对比

四、总结与建议
根据数据结构和需求选择:
简单对象浅合并:扩展运算符 {…a, …b}
需要兼容旧环境:Object.assign({}, a, b)
包含特殊类型(Date、Map等)的深度克隆:structuredClone()
复杂深度合并且已使用工具库:_.merge()
完全控制合并逻辑:自定义递归函数
structuredClone适用场景:
// 场景1:需要深度克隆包含Date、Map等特殊类型
const config = {
lastUpdated: new Date(),
permissions: new Set(['read', 'write']),
metadata: new Map()
};
const backup = structuredClone(config);
// 场景2:处理可能包含循环引用的对象
const objA = { name: 'A' };
const objB = { name: 'B', ref: objA };
objA.ref = objB; // 循环引用
const cloned = structuredClone(objA); // 正确处理
// 场景3:需要转移数据到Worker线程
const largeData = { /* 大数据对象 */ };
const worker = new Worker('worker.js');
worker.postMessage(structuredClone(largeData));
现代项目最佳实践:
// 1. 创建工具函数,根据情况选择最佳方案
export function smartClone(obj, deep = false) {
if (!deep) {
return Array.isArray(obj) ? [...obj] : { ...obj };
}
// 检查是否包含不支持的类型
const hasFunctions = JSON.stringify(obj, (key, value) => {
return typeof value === 'function' ? undefined : value;
}) === undefined;
if (hasFunctions || typeof structuredClone === 'undefined') {
// 回退到自定义深度克隆或JSON方法
return deepCloneFallback(obj);
}
return structuredClone(obj);
}
// 2. 对象合并的通用函数
export function mergeObjects(target, source, options = {}) {
const { deep = false, cloneStrategy = 'auto' } = options;
if (!deep) {
return { ...target, ...source };
}
if (cloneStrategy === 'structuredClone') {
return deepMergeWithClone(target, source);
} else if (cloneStrategy === 'json') {
// 仅用于可序列化数据
const cloned = JSON.parse(JSON.stringify(target));
return deepMergeRecursive(cloned, source);
} else {
// 默认使用lodash或自定义深度合并
return deepMergeCustom(target, source, options);
}
}
浏览器兼容性处理:
// 特征检测与polyfill
function safeStructuredClone(obj) {
if (typeof structuredClone === 'function') {
try {
return structuredClone(obj);
} catch (error) {
// 处理不支持的类型
console.warn('structuredClone failed:', error);
return fallbackClone(obj);
}
} else {
// 降级方案
return fallbackClone(obj);
}
}
function fallbackClone(obj) {
// 实现一个支持基本类型的深度克隆
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof Array) {
return obj.map(item => fallbackClone(item));
}
if (obj instanceof Object) {
const cloned = {};
for (const key in obj) {
if (Object.hasOwn(obj, key)) {
cloned[key] = fallbackClone(obj[key]);
}
}
return cloned;
}
// 其他类型直接返回(包括函数)
return obj;
}
最终建议总结:
默认选择扩展运算符:用于大多数浅合并场景,语法简洁性能好
深度合并考虑需求:优先使用structuredClone(现代浏览器),备选lodash或自定义函数
注意数据类型:有函数时不能用structuredClone和JSON方法
考虑性能:大数据量或频繁操作时避免深度克隆
做好兼容性:生产环境使用特征检测和降级方案
明确合并策略:特别是数组和特殊对象的处理逻辑
适用场景:

浅合并优先使用原生方法,深度操作评估是否需要引入库,根据实际数据结构和性能需求选择,保持团队代码风格统一。
总结
到此这篇关于JavaScript对象合并方法详解及最佳实践的文章就介绍到这了,更多相关JS对象合并方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
微信小程序用户授权获取手机号(getPhoneNumber)
这篇文章主要给大家介绍了关于微信小程序用户授权获取手机号的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2021-03-03
Bootstrap table 服务器端分页功能实现方法示例
这篇文章主要介绍了Bootstrap table 服务器端分页功能实现方法,结合实例形式详细分析了Bootstrap table 服务器端后台交互与分页功能相关操作技巧,需要的朋友可以参考下2020-06-06
javascript动态的改变IFrame的高度实现自动伸展
动态的改变IFrame的高度,实现IFrame自动伸展,父页面也自动神缩,实现原理很简单就是在IFrame子页面一加载的时候,调用父IFrame对象,改变其高度,感兴趣的朋友可以了解下2013-10-10
一文解决微信小程序button、input和image表单组件
在微信小程序开发中,input 用来实现文本输入,如输入用户名密码等等,下面这篇文章主要给大家介绍了关于如何通过一文解决微信小程序button、input和image表单组件的相关资料,需要的朋友可以参考下2022-08-08


最新评论