週末にデモプログラムを作成する時、ある要素の中から、指定された条件を満たすDOM要素を抽出する機能が必要だった為、下記のようなコードを作りました。
1 | const selectAll = el => condition => [el, |
考え方
実は、主な作業は2つだけです。
- 全ての要素を羅列します。
- 条件に満たしている要素をフィルターリングで抽出します。
コードを書けばこうなります。(allElements=全ての要素、condition=条件)
1 | const selectAll = (allElements, condition) => allElements.filter(condition) |
関数の再利用を考えたら、コンポジションを採用した方がいいでしょう。
1 | const selectAll = allElements => condition => allElements.filter(condition) |
1つ目の作業はどう実現するかは問題です。DOMはツリー構造なので、親要素の元に要素があり、その要素の中に、さらに子要素が存在する。ツリー構造のケースに対処する場合、再帰を使用することは一般的です。関数型風に書きたかったので、Array.prototye.mapとスプレッド構文を利用することにしました。DOM要素のchildrenはHTMLCollection型で、map関数が備えていません。よって、まずArray.from()
で配列に変換する必要があります。
1 | const selectAll = el => condition => [el, ...Array.from(el.children).map(child => selectAll(child)(condition))] |
しかし、上記のコードだと関数selectAll
の戻り値は配列になります。そのまま再帰してしまうと、配列内に配列が格納されることになります。reduceを使って、flatten効果を果たさせます。
1 | const selectAll = el => condition => [el, |
こんな考え方で、今回のコードを完成させました。
使用例
1 | // 全てのdiv要素を抽出する |
結論
やはりJSで関数型プログラミングするのは気持ちいいw