-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
84 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import yd_is_plainObject from '../is/plainObject.js'; | ||
import yd_is_symbol from '../is/symbol.js'; | ||
import yd_is_array from '../is/array.js'; | ||
|
||
const concatArrays = (originVal, newVal) => { | ||
if (yd_is_array(originVal) && yd_is_array(newVal)) { | ||
// concat logic | ||
return originVal.concat(newVal); | ||
} | ||
return newVal; // always return newVal as fallback!! | ||
}; | ||
|
||
const assignProp = (carry, key, newVal, originalObject) => { | ||
const propType = {}.propertyIsEnumerable.call(originalObject, key) ? 'enumerable' : 'nonenumerable'; | ||
if (propType === 'enumerable') carry[key] = newVal; | ||
if (propType === 'nonenumerable') { | ||
Object.defineProperty(carry, key, { | ||
value: newVal, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
}); | ||
} | ||
}; | ||
|
||
const mergeRecursively = (origin, newComer, compareFn) => { | ||
// always return newComer if its not an object | ||
if (!yd_is_plainObject(newComer)) return newComer; | ||
// define newObject to merge all values upon | ||
let newObject = {}; | ||
if (yd_is_plainObject(origin)) { | ||
const props = Object.getOwnPropertyNames(origin); | ||
const symbols = Object.getOwnPropertySymbols(origin); | ||
newObject = [...props, ...symbols].reduce((carry, key) => { | ||
const targetVal = origin[key]; | ||
if ((!yd_is_symbol(key) && !Object.getOwnPropertyNames(newComer).includes(key)) || (yd_is_symbol(key) && !Object.getOwnPropertySymbols(newComer).includes(key))) { | ||
assignProp(carry, key, targetVal, origin); | ||
} | ||
return carry; | ||
}, {}); | ||
} | ||
// newObject has all properties that newComer hasn't | ||
const props = Object.getOwnPropertyNames(newComer); | ||
const symbols = Object.getOwnPropertySymbols(newComer); | ||
const result = [...props, ...symbols].reduce((carry, key) => { | ||
// re-define the origin and newComer as targetVal and newVal | ||
let newVal = newComer[key]; | ||
const targetVal = yd_is_plainObject(origin) ? origin[key] : undefined; | ||
// When newVal is an object do the merge recursively | ||
if (targetVal !== undefined && yd_is_plainObject(newVal)) { | ||
newVal = mergeRecursively(targetVal, newVal, compareFn); | ||
} | ||
const propToAssign = compareFn ? compareFn(targetVal, newVal, key) : newVal; | ||
assignProp(carry, key, propToAssign, newComer); | ||
return carry; | ||
}, newObject); | ||
return result; | ||
}; | ||
|
||
/** | ||
* 合并对象 | ||
* @alias yd_object_mergeAndConcat | ||
* @category object | ||
* @param {object} target 目标对象 | ||
* @param {...any} otherObjects 其他对象 | ||
* @returns {object} 返回合并后的对象 | ||
* @author https://github.com/mesqueeb/merge-anything | ||
* @example yd_object_mergeAndConcat({a:1,b:[2,3],c:{d:4}},{a:2,b:[4,5],c:{e:6}}) // {a:2,b:[2,3,4,5],c:{d:4,e:6}} | ||
*/ | ||
export default (target, ...otherObjects) => { | ||
return otherObjects.reduce((result, newComer) => { | ||
return mergeRecursively(result, newComer, concatArrays); | ||
}, target); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { describe, it, expect } from 'vitest'; | ||
import yd_object_mergeAndConcat from './mergeAndConcat.js'; | ||
|
||
describe('yd_object_mergeAndConcat', () => { | ||
it('should return true', () => { | ||
const target = { a: 1, b: [2, 3], c: { d: 4 } }; | ||
const source = { a: 2, b: [4, 5], c: { e: 6 } }; | ||
expect(yd_object_mergeAndConcat(target, source)).toStrictEqual({ a: 2, b: [2, 3, 4, 5], c: { d: 4, e: 6 } }); | ||
}); | ||
}); |