實務上若由 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 還是會複製過去。
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()
實作,因此也是有相同問題。
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]
。
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 將忽略
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