Appearance
merge
merge 对象合并
用于将源对象的属性合并到目标对象,支持深度合并普通对象,数组可选择替换或拼接,默认不会修改原对象(返回新对象)。
一、引入与使用
支持两种方式引入:
ts
// 方式一:按需子路径引入(推荐)
import { merge } from '@cuixingjian/cui-utils/merge'
// 方式二:从包入口命名导出引入
import { merge } from '@cuixingjian/cui-utils'二、使用示例
ts
import { merge } from '@cuixingjian/cui-utils/merge'
const target = { a: 1, user: { name: 'cui', tags: ['ui'] } }
const source = { b: 2, user: { age: 20, tags: ['framework'] } }
// 深度合并,数组默认替换(replace)
const result1 = merge(target, source)
// result1: { a: 1, b: 2, user: { name: 'cui', age: 20, tags: ['framework'] } }
// 指定数组拼接(concat),不修改原对象(immutable: true)
const result2 = merge(target, source, { arrayStrategy: 'concat' })
// result2: { a: 1, b: 2, user: { name: 'cui', age: 20, tags: ['ui', 'framework'] } }
// 关闭深度合并,只进行浅覆盖
const result3 = merge(target, source, { deep: false })
// result3: { a: 1, b: 2, user: { age: 20, tags: ['framework'] } }三、API
| 方法 | 说明 | 类型 |
|---|---|---|
| merge | 将源对象属性合并到目标对象并返回合并结果 | (target: object, source: object, options?) => object |
参数
| 参数名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| target | 目标对象 | object | — |
| source | 源对象 | object | — |
| options | 合并选项 | MergeOptions | { deep: true, arrayStrategy: 'replace', immutable: true } |
MergeOptions
| 字段 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| deep | 是否进行深度合并(递归普通对象) | boolean | true |
| arrayStrategy | 数组合并策略:replace 替换;concat 拼接 | `'replace' | 'concat'` |
| immutable | 是否返回新对象(不修改原对象) | boolean | true |
返回值
| 名称 | 说明 | 类型 |
|---|---|---|
| result | 合并后的新对象 | object |
四、注意事项
- 仅对“普通对象”(原型为
Object.prototype或null)进行深度合并;其他类型(如Date、RegExp、Map、Set、函数等)直接覆盖引用。 - 数组默认替换,可通过
arrayStrategy: 'concat'拼接;不做去重处理。 - 默认不修改目标对象(
immutable: true);如需在原对象上合并可设置为false。
五、源码
展开查看
ts
// 源码来自 @cuixingjian/cui-utils/merge
export type AnyObject = Record<string | symbol, any>
export interface MergeOptions {
deep?: boolean
arrayStrategy?: 'replace' | 'concat'
immutable?: boolean
}
function isPlainObject(val: any): val is AnyObject {
if (val === null || typeof val !== 'object') return false
const proto = Object.getPrototypeOf(val)
return proto === Object.prototype || proto === null
}
export function merge<T extends AnyObject>(
target: T,
source: AnyObject,
options: MergeOptions = {}
): T {
const { deep = true, arrayStrategy = 'replace', immutable = true } = options
const out: AnyObject = immutable ? { ...target } : (target as AnyObject)
const keys = Reflect.ownKeys(source)
for (const key of keys) {
const sVal = (source as any)[key]
const tVal = (out as any)[key]
if (Array.isArray(sVal)) {
if (arrayStrategy === 'concat') {
const base = Array.isArray(tVal) ? tVal.slice() : []
;(out as any)[key] = base.concat(sVal.map((v) => (isPlainObject(v) ? { ...v } : v)))
} else {
;(out as any)[key] = sVal.map((v) => (isPlainObject(v) ? { ...v } : v))
}
continue
}
if (deep && isPlainObject(sVal) && isPlainObject(tVal)) {
;(out as any)[key] = merge({ ...tVal }, sVal, { deep, arrayStrategy, immutable: false })
continue
}
;(out as any)[key] = sVal
}
return out as T
}