deepmerge-plus
Version:
用於深度(遞迴)合併 JavaScript 物件的函式庫 / A library for deep (recursive) merging of JavaScript objects
193 lines (149 loc) • 5.27 kB
Markdown
# deepmerge 與 lodash 函式比較
# deepmerge vs Lodash Function Comparison
## 測試結果總覽 / Test Results Overview
| Lodash 函式 | deepmerge 對應方式 | 結果 | 說明 |
|------------|------------------|------|------|
| `_.assign` | 直接使用 deepmerge | ✅ isEqual: true | 淺層合併行為一致 |
| `_.assign` (多來源) | 使用 deepmergeAll | ✅ isEqual: true | 多物件依序合併 |
| `_.merge` | 直接使用 deepmerge | ✅ isEqual: true | 深度合併行為一致 |
| `_.merge` (陣列) | deepmerge 預設 | ⚠️ isEqual: false | deepmerge 串接,lodash 替換 |
| `_.merge` (陣列) | 自訂 arrayMerge | ❌ isEqual: false | 無法完全模擬 lodash 行為 |
| `_.defaults` | keyValueOrMode: true | ⚠️ isEqual: false | keyValueOrMode 只影響巢狀物件,不影響根層級 |
| `_.defaultsDeep` | keyValueOrMode: true | ❌ isEqual: false | 嘗試 1 - 仍覆蓋現有屬性 |
| `_.defaultsDeep` | isMergeableObject: false | ❌ isEqual: false | 嘗試 2 - 導致整體覆蓋 |
| `_.defaultsDeep` | keyValueOrMode + arrayMerge | ❌ isEqual: false | 嘗試 3 - 無法模擬 |
## 詳細比較 / Detailed Comparison
### 1. _.assign 等價 / Equivalent
```typescript
// deepmerge
const result = deepmerge({ a: 1, b: 2 }, { b: 3, c: 4 });
// 結果 / Result: { a: 1, b: 3, c: 4 }
// lodash
const result = _.assign({}, { a: 1, b: 2 }, { b: 3, c: 4 });
// 結果 / Result: { a: 1, b: 3, c: 4 }
```
**結論 / Conclusion**: ✅ 完全相同 / Identical
### 2. _.merge 等價 / Equivalent
```typescript
// deepmerge
const result = deepmerge(
{ a: 1, b: { c: 2, d: 3 } },
{ b: { d: 4, e: 5 }, f: 6 }
);
// 結果 / Result: { a: 1, b: { c: 2, d: 4, e: 5 }, f: 6 }
// lodash
const result = _.merge(
{},
{ a: 1, b: { c: 2, d: 3 } },
{ b: { d: 4, e: 5 }, f: 6 }
);
// 結果 / Result: { a: 1, b: { c: 2, d: 4, e: 5 }, f: 6 }
```
**結論 / Conclusion**: ✅ 完全相同 / Identical
### 3. 陣列處理差異 / Array Handling Difference
```typescript
// deepmerge (預設串接 / default concat)
const result = deepmerge(
{ items: [1, 2, 3] },
{ items: [4, 5] }
);
// 結果 / Result: { items: [1, 2, 3, 4, 5] }
// lodash (替換 / replace)
const result = _.merge(
{},
{ items: [1, 2, 3] },
{ items: [4, 5] }
);
// 結果 / Result: { items: [4, 5, 3] }
```
**結論 / Conclusion**: ⚠️ 不同 / Different
**嘗試模擬 / Attempt to simulate**:
```typescript
// 使用自訂 arrayMerge
const result = deepmerge(
{ items: [1, 2, 3] },
{ items: [4, 5] },
{ arrayMerge: (_target, _source) => _source }
);
// deepmerge 結果 / deepmerge result: { items: [4, 5] }
// lodash 結果 / lodash result: { items: [4, 5, 3] } (保留 target 第三個元素 / keeps target's third element)
// 無法完全模擬 / Cannot fully simulate
// isEqual: false
```
### 4. _.defaults 差異 / _.defaults Difference
```typescript
// deepmerge (keyValueOrMode: true)
const result = deepmerge(
{ a: 1, b: 2 },
{ b: 3, c: 4 },
{ keyValueOrMode: true }
);
// 結果 / Result: { a: 1, b: 3, c: 4 } (b 被覆蓋 / b overwritten)
// lodash
const result = _.defaults({ a: 1, b: 2 }, { b: 3, c: 4 });
// 結果 / Result: { a: 1, b: 2 } (只添加 c:4 / only adds c:4)
```
**結論 / Conclusion**: ⚠️ 不同 / Different
**原因 / Reason**: `keyValueOrMode: true` 只影響巢狀物件,不影響根層級屬性
### 5. _.defaultsDeep 差異 / _.defaultsDeep Difference
```typescript
// deepmerge (keyValueOrMode: true)
const result = deepmerge(
{ a: 1, b: { c: 2, d: 3 } },
{ b: { d: 4, e: 5 }, f: 6 },
{ keyValueOrMode: true }
);
// 結果 / Result: { a: 1, b: { c: 2, d: 4, e: 5 }, f: 6 }
// lodash
const result = _.defaultsDeep({ a: 1, b: { c: 2, d: 3 } }, { b: { d: 4, e: 5 }, f: 6 });
// 結果 / Result: { a: 1, b: { c: 2, d: 3 } }
```
**結論 / Conclusion**: ❌ 不同 / Different
**嘗試次數 / Attempts**:
1. ❌ keyValueOrMode: true - 仍覆蓋現有巢狀屬性
2. ❌ isMergeableObject: () => false - 導致整體覆蓋
3. ❌ keyValueOrMode + arrayMerge - 無法模擬
**放棄原因 / Give up reason**: lodash _.defaultsDeep 的行為無法透過現有選項完全模擬
## 實作選項參考 / Implementation Options Reference
### 深度合併 (Deep Merge)
```typescript
deepmerge(target, source)
```
### 淺層合併 (Shallow Merge)
```typescript
deepmerge(target, source, {
isMergeableObject: () => false
})
```
### 陣列替換 (Array Replace)
```typescript
deepmerge(target, source, {
arrayMerge: (_target, _source) => _source
})
```
### 保留目標值 (Preserve Target Values)
```typescript
deepmerge(target, source, {
keyValueOrMode: true
})
```
## 結論 / Conclusion
| 函式 | isEqual | deepmerge 可完全模擬? |
|------|---------|----------------------|
| `_.assign` | ✅ true | 可以 |
| `_.assign` (多來源) | ✅ true | 可以 |
| `_.merge` | ✅ true | 可以 |
| `_.merge` (陣列) | ❌ false | 無法完全模擬 |
| `_.defaults` | ❌ false | keyValueOrMode 只影響巢狀 |
| `_.defaultsDeep` | ❌ false | 無法模擬 |
**主要差異**:
1. 陣列處理:deepmerge 預設串接,lodash 替換
2. defaults 行為:deepmerge 無法完全模擬 lodash 的「只填充缺失鍵」行為