linq.jsをjQueryと一緒に使う
- 2010-04-15
linq.jsとjQueryを一緒に使うとするとどうなるのかな、という今まで微妙に避けてきた話。実用的なことを考えるなら避けて通れないのですが、実用的なことなんて考えたこともなかった!今まで!すみません。というわけで、少し考えてみます。あ、Linq to Xml(linq.xml.js)はボツの方向で行きます。RxJSを見習って、jQueryと仲良くやる方向で考えるつもりです。割とイイ線行ってたかなあ、とは思うんですが、クロスブラウザ対応の面倒くささが半端なくて実装しきる気力が持ちそうにないのと、やっぱセレクタ操作が冗長になりすぎてダメだったかなあ、なんて思ってます。
```javascript var p_arr = from p_ele in $("p") where "hoge" in p_ele.classes select p_elefor(var p in p_arr){ p.toggleClass("hilight"); }
こんな風なことができるのかと思ったがそんなわけはなく。<br /> <a href="http://d.hatena.ne.jp/beta_magnus/20100412/1271070326">Linq.js - 人生がベータ版</a> </blockquote> お試しありがとうございます。この例は、出来るといえば出来るし、出来ないといえば出来ないです。まず、クエリ構文では書けなくて、というのはともかくメソッド構文で実際にlinq.jsで組んでみるとこうなります。 ```javascript E.From($("p")) // 内包するDOM要素を列挙 .Select("jQuery($)") // 単一要素のjQueryオブジェクトにラップ .Where(function (q) { return q.attr("class") == "hoge" }) .ForEach(function (q) { q.toggleClass("hilight") }); // jQueryで同じような形にするならこうでしょうか $("p.hoge").each(function () { var q = $(this); q.toggleClass("hilight"); });
FromでjQueryの選択された要素を列挙に変換します。jQueryの列挙はjQueryオブジェクトではなく、DOM要素をそのまま返すので(これは.eachで回した時も一緒ですね)、jQueryのメソッドを使いたい時は再度ラップしてあげます。ただまあ、単純なフィルタリングなら、jQueryのセレクタで書いたほうが当然すっきり仕上がりますね。更にまあ、そもそもeachする必要はなく、
// jQuery自体が集合を扱うので一行で書けるんですよね…… $("p.hoge").toggleClass("hilight");
となってしまうわけで、DOMから選択してDOMに作用を加える、という一連のjQueryチェーンで綺麗に成り立っている場合に、linq.jsを挟む余地はありません。jQuery自体が集合を含有しているので、jQueryだけで綺麗に完結しちゃうんですね。そしてlinq.jsは、それ自体はクロスブラウザ対応だったりのDOM操作は一切持っていないので、その辺はjQueryにお任せします。そうなると、どうしても出番が限られてくるという。
じゃあ無価値なのかといえば勿論そんなことはなくて、DOMをDOMのまま扱って抽出して作用を加えるのではなく、そこからテキストだったり数値を抽出する、というシーンでは生き生きとします。DOMの選択、フィルタリングまではjQueryのセレクタで行ったらlinq.jsに渡す。数値だったら集計系のメソッドが使えるし、他にもテーブル内の文字をキーにして複数テーブルの結合(join)、なんかも簡単に出来ます。
ところで、 E.From($("selector")).Select("jQuery($)") というのは定型文になるので、jQuery自体に拡張してしまいます。こんなんでもプラグインって呼んでいいですか?(プラグインとしての部分は一行でも、繋がってる先はある意味ヘビー級なので)
// これでjQueryオブジェクトからtoEnumerable()を呼ぶとlinqが使える jQuery.fn.toEnumerable = function () { return E.From(this).Select("jQuery($)"); } // 例えば、input要素の数値を合計する、とか var sum = $("input").toEnumerable() .Select("parseInt($.val())") .Sum();
割と便利。かな?具体例に乏しくて非常に説得力に欠ける感じですが、良ければ使ってやってください。