Ramdaは関数型プログラミングを補助するJavaScriptライブラリだけど、それとは別に便利な関数もたくさん入っている。便利なものをカウントダウン形式に10個紹介するよ。気になる関数があればAPIドキュメント: http://ramdajs.com/docs/ を見てみよう。

#01. path: 安全なプロパティアクセス

Objectを連想記憶/辞書型/ハッシュテーブルとして使う際に、深いところにあるデータを抜き取るのがめんどくさい。

const obj = {
  cache: {
    user: {
      id: 123,
      name: 'alice',
    },
    contents: {
     ...
    },
}

例えば上記の例だと、名前をとってくるのには name = obj.cache.user.name とやればいいんだけど、例えば obj.cache.user というキーが存在しない場合は、例外がスローされちゃう。めんどい。そんな時は R.path の出番。

R.path(['cache','user','name'], obj) // -> 'alice'
R.path(['cache', 'user', 'name'], { cache: {} }) // -> undefined
R.path(['cache', 'user', 'name'], {}) // -> undefined

#02. range: 連続する数値の生成

[1,2,3,4,5] などのように連続するN個の整数からなる配列を作るのが有効な場面がある。range を使うとすぐ作れる。N回なんかの処理をしたい!とか、オフセットを付けたいとか。

// 1+2+3+....10
R.range(1, 11).reduce((a, x) => a + x, 0); // -> 55
// generate url
R.range(1,5).map(i => `/index?page=${i}`) // -> ['/index?page=1','/index?page=2'... ]

関連: 同じものを何個も作りたい、ってときは repeat もあるけど、癖があるので注意。

#03. scan: reduceっぽい何か

reduce は、配列の値を1個ずつ折りたたんで最終的に1つの値にするけど、scanは同じように折りたたむんだけど、途中経過を配列に保持してくれる。reduceのデバッグに使うのもよし、以下の例のように、いい使い道もあるかも。

// calc factorial
R.scan((a, x) => a * x, 1, R.range(1, 6)) // [ 1, 1, 2, 6, 24, 120 ]

#04. clone: ディープコピー

Ramda もディープコピー機能を提供している。普通はLodashとか使うのかもしれないけど、せっかくRamdaをインポートしてるなら使うのもいいかもね。

const obj1 = { a: [1, 2] };
const obj2 = R.clone(obj1)
obj2.a.pop();
obj1.a.length === obj2.a.length // -> false

#05. pipe: 関数をつなげてつなげて

左から右にどんどん関数を適用していくパターン。最初の関数以外は、引数を1つしかとってはいけない。

const getName = obj => obj.name;
const getMsg = name => `hello ${name}`;
const toUpper = str => str.toUpperCase();
const toLoud = str => str.concat('!');

const f = R.pipe(getName, getMsg, toUpper, toLoud);
f({ name: 'alice' });// -> HELLO ALICE!

右から左にどんどん関数を適用するのは compose だけどこっちのほうが直観的に使える。

#06. once: 絶対に2回以上呼ばせない

何回呼んでも、実際には 2回目以降は呼ばないというスゴ技。返り値は1回目のものが使いまわされる。

const greetOnce = R.once(() => { console.log('hello'); });
greetOnce()
greetOnce()
greetOnce()
greetOnce()
// hello is printed only once.

#07. memoizeWith: 関数呼び出し結果の保存

もし作った関数がpureであれば、同じ引数で何回も関数呼び出しをするのは計算リソースの無駄づかい。1回関数呼び出しをしたら返り値を覚えておいて、2回目以降は覚えておいた返り値を渡すようにする。

const echo = (val) => { console.log(`calc ${val}`); return val;}
const ecoEcho = R.memoizeWith(R.identity, echo);
ecoEcho(1);
ecoEcho(1);
ecoEcho(2);
// print two lines only.

第一引数は、キー作成ロジックであり、よくわからなければR.identity(引数をそのままキーにする)にしておけばよい。

#08. allPass: N回filterする

isXXX() というようなチェックを何回もするような時、例えば、配列を何回もfilterするようなときは、allPassを使うとすっきりした見た目になる。すっきりした見た目はエラーがすくなく、コメントの必要すらなくなる

const isNegative = d => d < 0;
const isEven = d => d % 2 === 0;
const isAllIWant = R.allPass([isNegative, isEven]);
R.range(-4, 10).filter(isAllIWant); // -> [ -4, -2 ]

#09. groupBy: 配列要素をグループ化

配列の要素をいくつかのグループに分けたいことがある。素数とそうでない数だとか、スコアによってAクラス〜Dクラスに分けるとか。groupByはそのための自然な手段を提供してくれる

const byTruth = R.groupBy(o => (o ? 'T' : 'F'));
const arr = [1, 0, -1, '', undefined, null, {}, [], 'hello'];
byTruth(arr);
// -> { T: [ 1, -1, {}, [], 'hello' ], F: [ 0, '', undefined, null ] }

#10. flatten: 配列をきれいに

Qiitaで独自実装している人をよくみる。個人的には使ったことがない。

R.flatten( [1, [2,3], [4,5,[6]] ] ) // -> [1,2,3,4,5,6]
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.