LINQ to ObjectのメソッドをJavaScriptの個別のモジュールとして使うためのライブラリ

LINQ to ObjectのメソッドをJavaScriptの個別のモジュールとして使うことのできるライブラリを作った。 これは元々Feedponで利用するために作ったのもので、現在はライブラリ単体として切り出している。

@emonkak/enumerable

なお、今回特に解説しないが本ライブラリはPHP版のものも存在する。

Emonkak\Enumerable

設計

この手のシーケンス処理のためのライブラリは膨大なメソッド(関数)を提供するので、そのライブラリに依存するスクリプトのサイズが大きくなりがちだ。 そのため、lodashRxJSなどのライブラリは個別のメソッドをモジュールとしても提供している。 個別に提供することで必要なものだけを読み込むようになるので、スクリプトのサイズ減らすことができるからだ。

今回作成した@emonkak/enumerableも同様で、メソッドを個別にモジュールとして提供している。 さらに、それらのモジュールが他のモジュールになるべく依存しないようにすることで、スクリプトサイズの増加を最小限に抑えている。

では、lodashとの違いはどこにあるのかというと、APILINQベースであるということがまずある。 LINQAPIは一般的なシーケンス処理の設計とは異なり、Select() Where() などSQL文を彷彿とさせる命名がなされている。 慣れていないと少々とっつきにくいが、APIとしての機能性はとても優れているように思う。 特に Join()GroupJoin() のような結合処理ができるのはLINQならではで、他のライブラリ等だとあまり提供されない。 実際に開発する動機となったのはこの2つのメソッドが必要になったからだ。

もう一つの違いとして、@emonkak/enumerableではGeneratorを使って実装されたIteratorをターゲットにしたAPIなので、シーケンス処理が遅延される。 そのため、返り値として配列が必要な場合は適宜変換が必要だ。 Generatorを使っているのでサポート環境が限られるが、モダンブラウザではサポートが進みつつある。 サポート環境を絞ればトランスパイルなしで利用できるだろう。

使用例

import select from '@emonkak/enumerable/select';

Array.from(select.call([1, 2, 3], (x) => x * 2));  // => [2, 4, 6]

This-Binding Syntaxを使うことでメソッドチェインをすることができる。

import select from '@emonkak/enumerable/select';
import where from '@emonkak/enumerable/where';
import toArray from '@emonkak/enumerable/toArray';

[1, 2, 3]
    ::where((x) => x % 2 === 0)
    ::select((x) => x * 2)
    ::toArray();  // => [4]

しかし、This-Binding Syntaxはまだ提案段階なのでトランスパイルなしでは使用することはできない。 代替手段として拡張モジュールを使用することができる。 拡張モジュールは読み込むと、Enumerable クラスにメソッドが追加される。

import Enumerable from '@emonkak/enumerable';

import '@emonkak/enumerable/extensions/select';
import '@emonkak/enumerable/extensions/where';
import '@emonkak/enumerable/extensions/toArray';

new Enumerable([1, 2, 3])
    .where((x) => x % 2 === 0)
    .select((x) => x * 2)
    .toArray();  // => [4]

@emonkak/enumerable