JavaScript?對(duì)象合并方法詳解及最佳實(shí)踐
一、常用對(duì)象合并方法
1.1 展開(kāi)運(yùn)算符 (Spread Operator)
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const result = { ...obj1, ...obj2 };
// { a: 1, b: 3, c: 4 }
優(yōu)點(diǎn):
語(yǔ)法簡(jiǎn)潔直觀
ES6+ 原生支持
創(chuàng)建新對(duì)象,不影響原對(duì)象
缺點(diǎn):
淺拷貝(嵌套對(duì)象只復(fù)制引用)
無(wú)法合并復(fù)雜結(jié)構(gòu)(如數(shù)組、特殊對(duì)象)
不支持深度合并
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 被覆蓋
優(yōu)點(diǎn):
ES5+ 兼容性好
可合并多個(gè)對(duì)象
創(chuàng)建新對(duì)象(當(dāng)?shù)谝粋€(gè)參數(shù)為{}時(shí))
缺點(diǎn):
淺拷貝
會(huì)覆蓋同名屬性
無(wú)法處理getter/setter
1.3 手動(dòng)深度合并函數(shù)
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 }
優(yōu)點(diǎn):
可深度合并
高度可定制
控制合并策略
缺點(diǎn):
需要自己實(shí)現(xiàn)和維護(hù)
可能性能較低
需考慮循環(huán)引用
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 };
// 或手動(dòng)合并克隆后的對(duì)象
const merged = Object.assign(structuredClone(obj1), obj2);
優(yōu)點(diǎn):
真正的深度克?。òㄇ短讓?duì)象)
支持復(fù)雜類(lèi)型:Date、Map、Set、ArrayBuffer等
官方標(biāo)準(zhǔn),現(xiàn)代瀏覽器原生支持
處理循環(huán)引用
不共享任何引用
缺點(diǎn):
不能克隆函數(shù)、DOM節(jié)點(diǎn)、Error對(duì)象等
性能開(kāi)銷(xiāo)較大(特別是大對(duì)象)
Node.js 17+ 和現(xiàn)代瀏覽器才支持
不能自定義合并策略
只能克隆,需要配合其他方法實(shí)現(xiàn)合并
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);
優(yōu)點(diǎn):
功能強(qiáng)大,深度合并
支持自定義合并邏輯
處理各種邊緣情況
社區(qū)維護(hù),穩(wěn)定可靠
缺點(diǎn):
增加包體積
需要引入外部庫(kù)
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);
// 注意:這種方式有局限性,不處理函數(shù)、循環(huán)引用等
優(yōu)點(diǎn):
簡(jiǎn)單暴力
創(chuàng)建完全獨(dú)立的拷貝
缺點(diǎn):
丟失函數(shù)、undefined、Symbol等
無(wú)法處理循環(huán)引用
性能較差
二、其他特殊場(chǎng)景方法
2.1 深度合并庫(kù):deepmerge
import deepmerge from 'deepmerge';
const obj1 = { a: 1, b: { x: 1 }, arr: [1, 2] };
const obj2 = { b: { y: 2 }, arr: [3, 4] };
// 默認(rèn)合并
const result1 = deepmerge(obj1, obj2);
// { a: 1, b: { x: 1, y: 2 }, arr: [3, 4] }
// 數(shù)組合并策略
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 實(shí)現(xiàn)響應(yīng)式合并
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;
}
});
}
三、方法對(duì)比

四、總結(jié)與建議
根據(jù)數(shù)據(jù)結(jié)構(gòu)和需求選擇:
簡(jiǎn)單對(duì)象淺合并:擴(kuò)展運(yùn)算符 {…a, …b}
需要兼容舊環(huán)境:Object.assign({}, a, b)
包含特殊類(lèi)型(Date、Map等)的深度克?。簊tructuredClone()
復(fù)雜深度合并且已使用工具庫(kù):_.merge()
完全控制合并邏輯:自定義遞歸函數(shù)
structuredClone適用場(chǎng)景:
// 場(chǎng)景1:需要深度克隆包含Date、Map等特殊類(lèi)型
const config = {
lastUpdated: new Date(),
permissions: new Set(['read', 'write']),
metadata: new Map()
};
const backup = structuredClone(config);
// 場(chǎng)景2:處理可能包含循環(huán)引用的對(duì)象
const objA = { name: 'A' };
const objB = { name: 'B', ref: objA };
objA.ref = objB; // 循環(huán)引用
const cloned = structuredClone(objA); // 正確處理
// 場(chǎng)景3:需要轉(zhuǎn)移數(shù)據(jù)到Worker線(xiàn)程
const largeData = { /* 大數(shù)據(jù)對(duì)象 */ };
const worker = new Worker('worker.js');
worker.postMessage(structuredClone(largeData));
現(xiàn)代項(xiàng)目最佳實(shí)踐:
// 1. 創(chuàng)建工具函數(shù),根據(jù)情況選擇最佳方案
export function smartClone(obj, deep = false) {
if (!deep) {
return Array.isArray(obj) ? [...obj] : { ...obj };
}
// 檢查是否包含不支持的類(lèi)型
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. 對(duì)象合并的通用函數(shù)
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') {
// 僅用于可序列化數(shù)據(jù)
const cloned = JSON.parse(JSON.stringify(target));
return deepMergeRecursive(cloned, source);
} else {
// 默認(rèn)使用lodash或自定義深度合并
return deepMergeCustom(target, source, options);
}
}
瀏覽器兼容性處理:
// 特征檢測(cè)與polyfill
function safeStructuredClone(obj) {
if (typeof structuredClone === 'function') {
try {
return structuredClone(obj);
} catch (error) {
// 處理不支持的類(lèi)型
console.warn('structuredClone failed:', error);
return fallbackClone(obj);
}
} else {
// 降級(jí)方案
return fallbackClone(obj);
}
}
function fallbackClone(obj) {
// 實(shí)現(xiàn)一個(gè)支持基本類(lèi)型的深度克隆
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;
}
// 其他類(lèi)型直接返回(包括函數(shù))
return obj;
}
最終建議總結(jié):
默認(rèn)選擇擴(kuò)展運(yùn)算符:用于大多數(shù)淺合并場(chǎng)景,語(yǔ)法簡(jiǎn)潔性能好
深度合并考慮需求:優(yōu)先使用structuredClone(現(xiàn)代瀏覽器),備選lodash或自定義函數(shù)
注意數(shù)據(jù)類(lèi)型:有函數(shù)時(shí)不能用structuredClone和JSON方法
考慮性能:大數(shù)據(jù)量或頻繁操作時(shí)避免深度克隆
做好兼容性:生產(chǎn)環(huán)境使用特征檢測(cè)和降級(jí)方案
明確合并策略:特別是數(shù)組和特殊對(duì)象的處理邏輯
適用場(chǎng)景:

淺合并優(yōu)先使用原生方法,深度操作評(píng)估是否需要引入庫(kù),根據(jù)實(shí)際數(shù)據(jù)結(jié)構(gòu)和性能需求選擇,保持團(tuán)隊(duì)代碼風(fēng)格統(tǒng)一。
總結(jié)
到此這篇關(guān)于JavaScript對(duì)象合并方法詳解及最佳實(shí)踐的文章就介紹到這了,更多相關(guān)JS對(duì)象合并方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS棧stack類(lèi)的實(shí)現(xiàn)與使用方法示例
這篇文章主要介紹了JS棧stack類(lèi)的實(shí)現(xiàn)與使用方法,結(jié)合實(shí)例形式分析了棧的原理,以及javascript定義與使用棧的基本操作技巧,需要的朋友可以參考下2019-01-01
自適應(yīng)高度框架 ----屬個(gè)人收藏內(nèi)容
自適應(yīng)高度框架 ----屬個(gè)人收藏內(nèi)容...2007-01-01
Auntion-TableSort國(guó)人寫(xiě)的一個(gè)javascript表格排序的東西
Auntion-TableSort國(guó)人寫(xiě)的一個(gè)javascript表格排序的東西...2007-11-11
關(guān)于前后端json數(shù)據(jù)的發(fā)送與接收詳解
這篇文章主要給大家介紹了關(guān)于前后端json數(shù)據(jù)發(fā)送與接收的相關(guān)資料,文中通過(guò)示例代碼詳細(xì)介紹了關(guān)于flask中的json數(shù)據(jù)接收和前端發(fā)送json數(shù)據(jù)等內(nèi)容,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-07-07

