先に実行結果を。
// 元データ
const test1 = {
a: { aa: 1, ab: 2, ac: [31, 32, 33], },
b: { ba: 4, bb: [51, 52, 53], bc: 6, },
c: { ca: [71, 72, 73], cb: 8, cc: 9, },
}
// 差分
const test2 = {
a: { ab: 20, ac: [], },
b: { ba: 40, bb: [51], },
c: { ca: [71, 72, 73, 74, 75], cc: '9' },
d: { da: ['a', 'b', 'c'], db: 'd', dc: 'e', },
}
// マージ結果
deepMerge(test1, test2);
{
a: { aa: 1, ab: 20, ac: [] },
b: { ba: 40, bb: [ 51 ], bc: 6 },
c: { ca: [ 71, 72, 73, 74, 75 ], cb: 8, cc: '9' },
d: { da: [ 'a', 'b', 'c' ], db: 'd', dc: 'e' }
}
実装はこんな感じ。
// メインの関数
const deepMerge = (base, difference) => {
const merged = JSON.parse(JSON.stringify(base));
const diff = JSON.parse(JSON.stringify(difference));
merger(merged, diff);
return merged;
}
// これが再帰的に呼び出される
const merger = (merged, diff) => {
for (const key of Object.keys(diff)) {
if (!(key in merged)) {
// パラメータの追加
merged[key] = diff[key];
continue;
}
if (typeof diff[key] === 'object' && diff[key] !== null) {
// 配列の場合は要素数を合わせる
if (Array.isArray(diff[key])) {
merged[key] = merged[key].slice(0, diff[key].length)
}
// オブジェクトの場合は再帰呼び出し
merger(merged[key], diff[key]);
} else {
// パラメータの更新
merged[key] = diff[key];
}
}
}
あとがき
うーん、後から考えてみれば別に作る必要なかったかも。