點燈坊

學而時習之,不亦悅乎

使用 assoc() 新增 Property

Sam Xiao's Avatar 2019-08-04

若想對 Object 新增 Property,Ramda 提供了 assoc()

Version

macOS 10.14.5
VS Code 1.36.1
Quokka 1.0.238
Ramda 0.26.1

Add Property by Value

Imperative

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' }
];

let usrFn = arr => {
  let result = [];

  for (let x of arr) {
    result.push({ ...x, price: 200 });
  }

  return result;
};

console.dir(usrFn(data));

Imperative 會使用 for loop,先建立新的 result array,使用 ... spread operator 保留原本 array,並加上新的 price property 與其值 200,最後 push 進 result 回傳。

assoc004

Array.prototype.map()

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' }
];

let usrFn = arr => arr.map(x => ({ ...x, price: 200 }));

console.dir(usrFn(data));

ECMAScript 的 Array.prototype 也內建 map(),可直接傳入 map function。

一樣使用 ... spread operator 保留原本 array,並加上新的 price property 與其值 200

assoc000

Ramda

import { map, assoc } from 'ramda';

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' }
];

let usrFn = map(assoc('price', 200));

console.dir(usrFn(data));

若 property 是固定值,則使用 assoc() 相當簡單直覺。

assoc()
String -> a -> {k: v} -> {k: v}
複製原本 object 的 property 外,還可新增 property

String : 新 property 的 key

a:新 property 的 value

{k: v}:data 為原 object

{k: v} :回傳的新 object

assoc001

Add Property by Other Property

Imperative

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' }
];

let usrFn = arr => {
  let result = [];

  for (let x of arr) {
    result.push({ ...x, price: x.id });
  }

  return result;
};

console.dir(usrFn(data));

Imperative 會使用 for loop,先建立新的 result array,使用 ... spread operator 保留原本 array ,並加上新的 price property ,且其值為原本的 id,最後 push 進 result 回傳。

assoc005

Array.prototype.map()

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' }
];

let usrFn = arr => arr.map(x => ({ ...x, price: x.id }));

console.dir(usrFn(data));

ECMAScript 的 Array.prototype 也內建 map(),可直接傳入 map function。

一樣使用 ... spread operator 保留原本 array,並加上新的 price property 且其值為原本的 id

assoc002

Ramda

import { assoc, chain, map, prop } from 'ramda';

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' }
];

let mapFn = chain(
  assoc('price'),
  prop('id')
);

let usrFn = map(mapFn);

console.dir(usrFn(data));

目前 map() 的 map function 還帶有 x, 還不是 point-free,有進一步優化的空間嗎 ?

第 9 行

let mapFn = chain(
  assoc('price'),
  prop('id')
);

map() 的 map function 提出成為 mapFn()

assoc() 第一個參數為 key,我們指定為 price,第二個 argument 為 value,由於我們要根據 object 的 id property 建立 price,因此需提供 application function,運算後再傳給 assoc(),因此使用了 chain()

chain()

Chain m => (a → m b) → m a → m b
若 data 為 application function, chain(f, g)(x) = f(g(x), x)

assoc003

Conclusion

  • assoc() 只要配合固定值,則用起來很簡單
  • assoc() 要配合其他 property,則要配合 chain()prop()

Reference

Ramda, map()
Ramda, chain()
Ramda, assoc()
Ramda, prop()