點燈坊

失くすものさえない今が強くなるチャンスよ

使用 mergeOnly() 將兩個 Object 合併

Sam Xiao's Avatar 2019-10-21

實務上若由 User 傳入 Object 欲與 Default Object 合併,但 User 可能多傳了一些 Property,而我們只想取用 Default Object 有的 Property,多的 Property 忽略不計,Object.assign() 或 Ramda 的 merge() 會將多餘的 Property 也 merge 進來,因此不符合需求。

Version

macOS Catalina 10.15
VS Code 1.39.2
Quokka 1.0.256
ECMAScript 2018
Ramda 0.26.1
Wink-fp 0.1.14

Object.assign()

let data1 = {
  a: 1,
  b: 2,
  c: 3
};

let data2 = {
  b: 5,
  c: 2,
  f: 6
};

Object.assign(data1, data2); // ?

若使用 ECMAScript 原生方法,最接近的是 Object.assign(),唯多出來的 f property 還是會複製過去。

only000

Ramda

import { merge } from 'ramda';

let data1 = {
  a: 1,
  b: 2,
  c: 3
};

let data2 = {
  b: 5,
  c: 2,
  f: 6
};


merge(data1)(data2); // ?

Ramda 的 merge()mergeRight(),底層也是使用 Object.assign() 實作,因此也是有相同問題。

only001

mergeOnly()

let data1 = {
  a: 1,
  b: 2,
  c: 3
};

let data2 = {
  b: 5,
  c: 2,
  f: 6
};

let mergeOnly = obj1 => obj2 => 
  Object
    .keys(obj1)
    .reduce(function(a, k) {
      a[k] = obj2[k] || obj1[k]
      return a
    }, {});

mergeOnly(data1)(data2); // ?

自行實作 mergeOnly(),先使用 Object.keys() 取得 obj1 所有 key 的 array,再以此 array reduce() 成新的 object。

由於是 reduce() 成 object,因此初始值為 {},且 a 為 object。

a[k] = obj2[k] || obj1[k]

obj2[k] 有值則優先使用,若 obj2[k] 沒值為 undefined 則取 obj1[k]

only001

Object Spread

let data1 = {
  a: 1,
  b: 2,
  c: 3
};

let data2 = {
  b: 5,
  c: 2,
  f: 6
};

let mergeOnly = obj1 => obj2 => 
  Object
    .keys(obj1)
    .reduce((a, k) => ({...a, [k]: obj2[k] || obj1[k]}), {});

mergeOnly(data1)(data2); // ?

16 行

{...a, [k]: obj2[k] || obj1[k]}

ES2018 迎來了新的 object spread,有更精簡的寫法。

使用 ...a 展開,再用 {} 合併成新的 object。

Wink-fp

import { mergeOnly } from 'wink-fp';

let data1 = {
  a: 1,
  b: 2,
  c: 3
};

let data2 = {
  b: 5,
  c: 2,
  f: 6
};

mergeOnly(data1)(data2); // ?

wink-fp 已經內建 mergeOnly(),可直接使用。

mergeOnly()
{k: v} -> {k: v} -> {k: v}

將兩個 object 合併,若 property 相同則取後者,且只取前者有的 property,後者多出的 property 將忽略

only004

Conclusion

  • mergeOnly() 為實務上常用的功能,透過 Object.keys()Array.prototype.reduce(),我們也能組合出 Object.assign()merge() 所沒有功能

Reference

MDN, Object.assign()
Ramda, merge()
MDN, Object.keys()
MDN, Array.prototype.reduce()
MDN, Spread syntax