點燈坊

學而時習之,不亦悅乎

使用 path() 拆解 Object

Sam Xiao's Avatar 2019-08-09

若 Function 的 argument 是很深層的 object,可以使用 ECMAScript 2015 的 Object Destructuring 加以拆解,除此之外,也可以使用 Ramda 的 path()

Version

macOS Mojave 10.14.5
VS Code 1.36.1
Quokka 1.0.240
Ramda 0.26.1

Non Proint-free

import { assoc, map } from 'ramda';

let data = {
  data: {
    books: [
      { title: 'FP in JavaScript', price: 100 },
      { title: 'RxJS in Action', price: 200 },
      { title: 'Speaking JavaScript', price: 300 },
    ],
  },
};

let addProp = (k, v) => ({ data: { books } }) => map(assoc(k, v), books);

console.dir(addProp('desc', 'Not selected')(data));

由於 ECMAScript 的 object 特性,實務上常常會遇到層數很深的 object,ES6 提供了 object destructuring,讓我們可以在 parameter list 就加以解構,非常方便。

path000

Point-free

import { map, assoc, pipe, path } from 'ramda';

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

let addProp = (k, v) => pipe(
  path(['data', 'books']),
  map(assoc(k, v)),
);

console.dir(addProp('desc', 'not selected')(data));

(k, v) 由於是條件部分,無法省略,但 ({ data: { books } }) 屬 data 部分,是否有機會 point-free 呢 ?

path()
[Idx] → {a} → a | Undefined
將層數很深的 object 加以解構

[Idx]:array,描述要解構的 property

{a}:要解構的 object

a | Undefined:若能解構則回傳 a,若無法解構成回傳 undefined

13 行

let addProp = (k, v) => pipe(
  path(['data', 'books']),
  map(assoc(k, v)),
);

({ data: { books } }) 省略,直接由 pipe() 傳給 path() 第二個參數,而 path() 第一個參數則以 array 形式描述要拆解的 property,如同 object destructuring 一樣。

path() 解構之後,再將 array 傳給 map() 的第二個參數。

如此 addProp() 就 Point-free 了。

path001

Conclusion

  • 參數為 object 時,固然可以使用 object destructuring 加以解構,但也可使用 Ramda 的 path(),可讀性更好,還可以 point-free

Reference

Ramda, map()
Ramda, assoc()
Ramda, pipe()
Ramda, path()