jQuery vs MooTools

2009年5月 - Aaron Newton of Clientcide
翻訳: cu39

ここ最近、JavaScriptを使って何かを始めようとする人の多くは、使うべきライブラリを選ぶという、あるいは少なくとも、まず最初にどれから学ぶか選ぶという骨の折れるタスクに直面します。あなたがある会社のために働いているなら、その会社はきっとあなたが使うフレームワークをもう選んでいるでしょう。この場合、骨の折れるタスクとは言えなくなるかもしれません。もしこのようなケースで、かつ会社が選んだのがMooToolsであり、あなたがjQueryに慣れ親しんでいるならば、この文章はいくらか役に立つものとなるでしょう。

のように twitter で、結局のところ「MooToolsかjQueryか?」という点に要約されるポストを目にします。この文章はその選択を決める助けとなることを目的としています。

免責

私はMooToolsの開発者の一人で、MooToolsフレームワークに取り組んでいます。ブログでもMooToolsについて書いています。代表的なオンラインチュートリアルMooToolsの書籍も書きました。明らかに、いくらか偏った視点に立っています。また、そこまで頻繁にjQueryを使ってはいないことも指摘しておきます。もしあなたがjQuery開発者で、私がここで間違った説明をしているのを見つけたら、ぜひ私に連絡して問題点の修正を助けて下さい。ここでの私の目的は、人々に正確かつ役に立つ情報を提供することにあります―どちらかのフレームワークだけを売り込むことではありません。

目的

2つのフレームワークから選択を行う際の助けとなるためには、必然的に、両者がどのように違うのかを説明しなければなりません。まず私は、どちらも優れた選択肢だと言うことから始めたいと思います。ここであなたは間違った選択をする可能性はないのです。どちらのフレームワークにも長所と短所がありますが、しかし一般的に、どちらでも素晴らしい選択なのです。この2つの他にも掘り下げてみる価値を持ったフレームワークはあります。Dojo, Prototype, YUI, Extやその他、すべて素晴らしい選択です。実際にどれを選ぶかはむしろ、あなた固有のスタイルや成し遂げる必要のあることと関連してきます。この文章の目的はMooToolsとjQueryに焦点をしぼることにあります。この2つのフレームワークに関心を持つ人がますます増えているように私には感じられるからです。最後に、私は片方のフレームワークからもう一方のフレームワークへ乗り換えるよう説得しようとしているのではありません。この文書について、またなぜこれを書いたかについて、私のサイトClientcideのブログ記事でもう少し詳しく読むことができます。

目次

統計

jQueryコア MooToolsコア
ライブラリのファイルサイズ 55.9K 64.3K
機能
ライセンス MIT & GPL MIT
DOMユーティリティ yes yes
アニメーション yes yes
イベント処理 yes yes
CSS3セレクタ yes (サブセットの1つ) yes (サブセットの1つ)
Ajax yes yes
ネイティブオブジェクト拡張(Elementを除く) Array, Object, Stringに対して約10~15カ所 Array, Object, String, Function, Numberに対して約70~80カ所
継承 jQueryで直接にはサポートされない Classコンストラクタにより提供される
他に考慮すべき点
プラグイン plugins.jquery.com のディレクトリで数百もの非公式プラグインが提供されている 大まかに50ほどの公式プラグインが mootools.net/more で提供されている。非公式プラグインディレクトリは mootools.net/plugins
公式UIライブラリ yes no

jquery.com, mootools.net, wikipedia.comのデータにもとづいた情報

モットーはすべてを語る

jQueryのサイトに行くと、ページトップに次のように書かれています:

jQueryは高速で簡潔なJavaScriptライブラリです。HTMLドキュメントのトラバース、イベントハンドリング、アニメーション、およびAjaxインタラクションを単純化し、素早いウェブ開発を可能にします。jQueryはJavaScriptを書く方法を変えるようデザインされています。

……また、MooToolsのサイトへ行くと次の文章があります:

MooToolsは簡潔で、モジュール式で、オブジェクト指向のJavaScriptフレームワークであり、上級JavaScript開発者の仲介者〔the intermediate〕となるようデザインされています。MooToolsを使えば、強力で、柔軟で、クロスブラウザなコードを、エレガントで、ドキュメントが整った、一貫性のあるAPIを使って書くことができます。

私はどちらもよくまとめられていると思います。あなたが私に質問するとしても(これを読んでいるなら何かお持ちだと思いますが)、両フレームワークの優劣については聞かないでしょう。あなたがしたいことは上の2つのうちどちらでしょうか? 2つのフレームワークは異なることをしようとしています。両者が提供する機能は、重なっている部分もありますが、同じことをしようとしているわけではないのです。

jQueryの説明そのものはHTML、イベント、アニメーション、Ajax、ウェブ開発について語っています。MooToolsはオブジェクト指向性と強力で柔軟なコードを書くことについて語っています。jQueryは「JavaScriptを書く方法を変える」ことを切望しており、対するMooToolsは上級JavaScript開発者の仲介者となるべくデザインされていると言っています。

この考察のある部分は、フレームワークツールキットという意識の違いとして把握できるでしょう。MooToolsはフレームワークであり、JavaScriptを本来あるべき姿に実装しようとしています(MooToolsの作者達によれば)。その目的は、JavaScriptらしさを残したまますべてを拡張するAPIを実装することであり、DOMを扱うだけのものではないのです。jQueryはツールキットであり、様々なメソッド群が自己充足的なシステム内で簡単に使えるようになっており、DOMそのものをより気持ちよく使えるようデザインされています。まったくの偶然ですが、DOMは人々がJavaScriptを書くときに最も努力をかけるところなので、多くのケースではjQueryがあなたの必要をすべて満たすでしょう。

MooToolsで書くコードの多くは、なおJavaScriptらしく感じられるものです。言語としてのJavaScriptに興味を持っていないなら、MooToolsを学ぶのはつらい仕事になるでしょう。JavaScriptそのものと、JavaScriptを面白く、強力で、表現力豊かにするものに興味があるならば、個人的な考えではMooToolsがベターな選択だと思います。

学習曲線とコミュニティ

まずおおよその場合、jQueryのほうが学習しやすいでしょう。jQueryは口語体〔形式張らない易しいスタイル〕を持っており、プログラミングという感覚をほとんど感じさせません。JavaScriptを学ばずに急いで何かを作りたいなら、おそらくjQueryがベターな選択でしょう。MooToolsはそういうことの助けにはなりません。JavaScript初心者にとって、MooToolsの趣意を飲み込むのはやや難しいことだと言わざるを得ません。またjQueryを学ぶためのリソースは至るところにあります―少なくともMooTools用のものよりはずっと。

jQueryコミュニティ(jQueryの"Discussion" ページを参照)とMooToolsコミュニティ(IRC, メーリングリスト, 非公式フォーラム)を比較するとすぐに次の2つの点に気づくでしょう: 1) jQueryコミュニティはかなり大きい(上でも指摘した通り、習得の容易さに起因することだと思いますが、それだけではなく……)、そして 2) 彼らはより活発にライブラリを奨励〔promoting〕している。jQueryとMooToolsについて、例えばライブラリの使用者数やGoogleの検索クエリ数といった基準で比較してみれば、jQueryがかなり大きく差を広げているのがわかるでしょう。

あなたがMooToolsを考慮すべき理由を伝えるために、私はまず両フレームワークが何をするかについて少し語る必要があります。究極的には、どちらのフレームワークを選ぶかは、あなたが達成したいことと、あなたがどうプログラムするのが好きか(少なくともJavaScriptにおいて、もしプログラムすることが好きなら、ですが)に帰着するでしょう。

JavaScriptが適しているもの

この選択の一部は、JavaScriptを使って何をしたいのか問いかける意味があります。さあ、基本的なJavaScriptについて考えてみましょう。フレームワークを使わない、普通の昔ながらの単なるJavaScriptです。JavaScriptはネイティブなオブジェクトをいくつか提供します。例えばStrings, Numbers, Functions, Arrays, Dates, Regular Expressionsなどです。JavaScriptは継承モデルも提供します――プロトタイプ的継承〔prototypal inheritance〕と呼ばれるいくらか秘儀的なモデルです(あとでもう少し詳しく述べます)。こうした基礎的要素と継承概念は、あらゆるプログラミング言語が必要とする基礎事項〔bread and butter〕であり、ウェブブラウザやウェブやCSSやHTMLとはそもそもまったく関係ありません。マルバツゲーム〔tic-tac-toe〕、チェス、写真編集、ウェブサーバ、その他のどれともです。まったく偶然ですが、世に存在するJavaScriptのうち99%はウェブブラウザー上で実行され、私たちはそういうものだと考えています。ブラウザーのためのプログラミング言語であると。

ブラウザ、つまりDOMが、多くの場合においてJSを使う場になっているのは単なる偶然でしかないのだということを理解すること、また、JSはたくましくて表現力豊かなプログラミング言語であると理解することは、MooToolsとjQueryの違いを理解する助けとなるでしょう。

DOMだけではない

「ページ上の何かを取ってきてそれに対して何かをする」という言葉で厳密に表せるような作業をしたいケースを考えた場合、jQueryはベストな選択となるでしょう。非常に表現力豊かにページ上の振る舞いを記述できるシステムを提供する点においてjQueryはずば抜けており、その方法はしばしばプログラミングだと感じさせないものです。それでもなお、JavaScriptの残りの部分を使って何かをすることは可能ですが、DOMに焦点を合わせる限り―CSSプロパティを変更する、何かをアニメーションさせる、Ajaxを通してコンテンツを取ってくる、など―あなたが書くであろうことのほとんどはjQueryによってカバーされ、古く素朴なJavaScriptにはならないでしょう。jQueryはDOMに関わらないメソッドもいくつか提供します。例えば、配列をイテレートする仕組みも提供します― $.each(array, fn) ― あるいは例えば、文字列をトリムするメソッドも提供します― $.trim(str)。しかしこの種のユーティリティメソッドを大量には提供していません。それはむしろ素晴らしいことです。なぜなら、単にDOMから何か要素を取り出して、その全体をイテレートし、何らかのかたちで変更(HTMLを付け加える、スタイルを変える、クリックやマウスオーバー用のイベントリスナーを追加する、など)したいだけであれば、たいていの場合はそれ以上の何かは必要ないからです。

しかし、JavaScriptの能力全体を完全に視野に入れて考えるならば、jQueryはDOMの外側のものごとに焦点を合わせていないことがわかるでしょう。これはjQueryがとても学びやすい理由の一つでもありますが、同時にJavaScriptを書く助けとなる手段を制限してもいます。jQueryは単にDOMのためのソリッドなプログラミングシステムという以外の何者にもなろうとしないのです。継承や、JavaScript言語の全ネイティブ型の基礎ユーティリティに取り組んではいませんが、それは必要ないのです。文字列、日付、正規表現、配列、関数といちゃついてみたいならば、それも可能です。ただそれはjQueryが助けるべき事柄ではないだけです。言語としてのJavaScriptはあなたの足下にあります。jQueryはDOMをあなたの遊び場にしてくれますが、JavaScriptの残りの部分はその視野に入っていません。

MooToolsはこの点で途方もなく大きな違いがあります。DOMに対して排他的に焦点を合わせるのでなく(ただし、少し詳しく言うと、MooToolsはjQueryの機能のすべてを提供しますが、それをかなり異なるやり方で達成しています)、言語全体を視野に入れているのです。jQueryがDOMをあなたの遊び場にするならば、MooToolsはJavaScriptそのものをあなたの遊び場にすることを目指しています。そして、これが学習を困難にする理由の一つでもあります。

JavaScriptの継承モデル

JavaScript言語は継承についていくつかの実に驚くべき仕組みを持っています。初心者にとっては関数型言語です。つまりJavaScriptは関数を高階オブジェクトとして扱います。関数も、他のあらゆるオブジェクト―例えば文字列や数値―と同じように、変数として渡すことができるわけです。JavaScriptはこの概念を念頭に置いて設計されており、この方法で書くことによりメソッドやパターンの多くが最も良く機能します。これは次の二つの違いに表れます:

for (var i = 0; i < myArray.length; i++) { /* do stuff */ }

myArray.forEach(function(item, index) { /* do stuff */ });

JavaScriptの持つ継承モデルは、完全に独特というわけではありませんが、プログラミング言語の中では少なくとも珍しい部類のものです。クラスを定義し、サブクラスにより継承可能にするという代わりに、プロトタイプ的継承を通じてモデルを伝えるのです。これはつまり、あるオブジェクトが他のオブジェクトを直接継承できることを意味します。他のオブジェクトを継承するあるオブジェクトのあるプロパティを参照したとすると、JavaScriptはまず子オブジェクトのプロパティを探査し、もし見つからない場合は、親オブジェクトのプロパティを探します。これが、あるメソッドが、例えば配列に対して動作する方法なのです。次のようにタイプしたとすると:

[1,2,3].forEach(function(item) { alert(item) }); // 1, 2, 3と順にアラートを表示

"forEach" メソッドはあなたが宣言した配列([1,2,3])のプロパティではなく、全配列のプロトタイプのプロパティなのです。あなたがこのメソッドを参照したとき、JavaScriptはforEachと呼ばれるメソッドをあなたの配列から探し、見つからない場合は、全配列のプロトタイプから探します。このことは、forEachメソッドが全配列につき一つずつメモリ上にあるのでなく、配列のプロトタイプのためだけにメモリ上にあることを意味しています。これは非常に効率的で、ものすごく強力です。(ちなみに、MooToolsではforEachメソッドをeachにエイリアスしています)

自己参照

Javascriptには "this" という特別な語があります。 "this" について簡潔にまとめるのは私にとって難しいことなのですが、しかし原則として、 "this" は現在のメソッドが帰属しているオブジェクトのことです。 "this" により、オブジェクトが自分自身とそこに属するメソッドを内部的に参照できるようになっています。もし "this" が無かったらそれを行う手段はなくなってしまいます。これが重要になるのは、子オブジェクトを作成し、そのオブジェクトのインスタンスをたくさん作ったときです。あるオブジェクトのメソッドは this 以外にどういう方法で自分自身を参照できるのでしょう? 子ではなく、親オブジェクトの現時点のメソッドのコピーが存在するとき、 "this" キーワードはこれらインスタンスがそれぞれの固有の状態を参照できるようにしてくれます。("this" キーワードについてのもっと完全な解説がここにあります。また Mozilla にも解説があります

"this" キーワードは、他のオブジェクトを継承しているオブジェクトが自分自身を参照できるようにしています。しかし "this" を通じて他のなにかを参照したいこともあるでしょう。これは「バインディング」と呼ばれており、そこではあるメソッドに対して通常とは異なる "this" を定義します。 Array の "each" メソッドでは第2引数を使ってバインドするオブジェクトを定義できます。次に示すのは、通常と異なる "this" を渡したい場合の例です:

var ninja = {
    weapons: ['刀', '手裏剣', 'エクスプローディング・パーム'],
    log: function(message) {
        console.log(message);
    },
    logInventory: function() {
        this.weapons.each(function(weapon) {
			// "this" にninjaを示してもらいたい……
            this.log('この忍者は ' + weapon + ' で殺すことができる');
        }, this); // ので、 "this" (=ninja)をArray.eachに渡す
    }
};
ninja.logInventory(); 
// この忍者は 刀 で殺すことができる
// この忍者は 手裏剣 で殺すことができる
// この忍者は エクスプローディング・パーム で殺すことができる

上の例では ninja (logInventory メソッド内での "this" にあたる)を、配列へ渡すメソッドにバインドしています。この結果、私たちは ninja の log プロパティを参照できることになります。もしこうしなかった場合、 "this" は window を参照してしまいます。

これらは単に、JavaScriptが提供する強力さと表現能力―継承、自己参照とバインディング、能率的なプロトタイププロパティなど―の例にすぎません。ただし悪いニュースなのですが、素朴なJavaScriptでは、これらの強力さが実用的で使いやすいものになっているわけではありません。そしてMooToolsのスタート地点はまさにここなのです。MooToolsはこうした種類のパターンを、簡単でもっと気持ちよく使えるものに変えてくれます。あなたはもっと抽象的なコードを書くことになるでしょうが、これは長い目で見れば良いことです―パワフルなことです。これらのパターンにどういう価値があり、どのように使えば適切なのかを学ぶには、たしかに努力が要ります。しかしその努力と表裏一体の結果として、あなたが書くコードは非常に再利用しやすく、しかも容易にメンテナンスできるものになるはずです。これら2つのことについて手短にもう少し語りたいと思います。

MooToolsはJavaScriptそのものをもっと楽しくする

MooToolsは、JavaScriptのAPIそのものをより安定感があり首尾一貫したものへと変えることに焦点を合わせているため、「JavaScriptを書く方法を変える」インターフェースを提供することにはあまり注力しておらず、むしろJavaScriptを全体としてストレスの少ないものへ変えることに集中しています。MooToolsはJavaScript言語に対する拡張なのです。MooToolsはJavaScriptをあるべき姿にしようと試みます。コアライブラリのかなり多くの部分はFunction, String, Array, Number, Elementやその他のプロトタイプを増大させるために費やされます。もう一つ大きなことは、コアライブラリがClassと呼ばれる関数を提供することです。

多くの人の目には、ClassがJavaやC++のような古典的継承モデルを作り出そうとするもののように見えるでしょう。でも違うのですClassが行うのは、JavaScriptのプロトタイプ型継承モデルを、あなたや私がもっと簡単にアクセスでき、強みを活かせるものにすることなのです。ただしこれらのコンセプトがMooTools固有のものではないことも付け加えておきます(他のフレームワークも同じような機能を提供しています)。しかしこれら2つのコンセプトはjQueryに無いものです。jQueryは継承システムを提供せず、またネイティブオブジェクト(Function, String, etc)の拡張も行いません。このことはjQueryの欠陥ではありません。そうではなくて、jQueryの開発者たちは異なる目標を念頭にツールキットをデザインしているのです。MooToolsはJavaScriptをもっと楽しいものにすることを狙い、jQueryはDOMをもっと楽しいものにすることを狙っています。そしてそれぞれの設計者は自分の視野を各々のタスクの範囲内に制限することを選んでいるわけです。

jQueryはDOMをもっと楽しくする

そして、これこそjQueryのほうが近づきやすい理由なのです。jQueryはJavaScriptの内側から外側まですべて学ぶことを求めてきません。jQueryはあなたをプロトタイプ的継承やバインディングや "this" やネイティブ・プロトタイプと一緒に未知の深淵へ投げ捨てることはしません。公式チュートリアルからjQueryを始めると、あなたは初めてのjQueryのコード例としてこれを見るはずです:

window.onload = function() {
    alert("welcome");
}

and here's the third:

$(document).ready(function() {
    $("a").click(function(event) {
        alert("Thanks for visiting!");
    });
});

the MooTools bookMooTools tutorial(両方とも私が書いたものです)を読んでみる場合、まったく違う場所からスタートすることになります。あなたは最初のほうは軽く跳ばして手早くエフェクトやDOMについて学ぶこともできますが、もしMooToolsをきちんと学びたいと思うなら、まずClassのような物事から始めなければなりません。そして、私は次のことも認めます: あなたがプログラミング初心者であるか、またはJavaScriptについてのすべてを学ぶ必要がなくただ自分のサイトで動作する何かを得たいと思っているだけだとしたら、きっとjQueryのほうがフレンドリーに見えることでしょう。

他方、JavaScriptそのものを学びたいと思うなら、MooToolsは素晴らしい手段となります。MooToolsは、JavaScriptが近々持つことになるものがたくさん実装されています(多くのメソッドやネイティブオブジェクトはJavaScript 1.8仕様やその先のものです)。プログラミングに、特にオブジェクト指向および関数型プログラミングに親しんでいるならば、MooToolsにはとても刺激的で表現力豊かなデザインパターンがたくさんあることでしょう。

あなたができることは何でも、私はもっとよくできる

jQueryで可能なことは、しばしば同等のものがMooToolsにもあります。MooToolsで可能なことは、jQueryのコードを使ってエミュレートする方法がない場合がしばしばあります。jQueryはDOMに焦点を合わせているからです。MooToolsはjQueryよりも幅広い機能を持っていますが、jQueryはそれらと同じことをするのを妨げたりはしません。例えば、jQueryにはいかなる継承システムもついてきませんが、それでいいのです。お望みならばMooToolsのClassをjQueryと組み合わせて使うことも(あるいは独自に書くことも)できます。jQueryの継承プラグインさえ存在します(私は使ったことがありませんが、ほとんど同じ機能を提供してくれるものと思います)。

上に引用したjQueryの例を見てみると:

$(document).ready(function() {
    $("a").click(function(event) {
        alert("Thanks for visiting!");
    });
});

そしてこれをMooToolsに翻訳するなら、次のようになります:

window.addEvent('domready', function() {
    $$('a').addEvent('click', function(event) {
        alert('Thanks for visiting!');
    });
});

よく似ていませんか?

jQueryからもう少し複雑な例を:

$(document).ready(function() {
    $("#orderedlist li:last").hover(function() {
        $(this).addClass("green");
    },
    function() {
        $(this).removeClass("green");
    });
});

そして、MooToolsの場合は:

window.addEvent('domready',function() {
    $$('#orderedlist li:last-child').addEvents({
        mouseenter: function() {
            this.addClass('green');
        },
        mouseleave: function() {
            this.removeClass('green');
        }
    });
});

こちらもよく似ています。私はMooTools版のほうがより明確であると主張しますが、そのせいでより冗長になっているのも確かです。MooToolsのコードを読んでみると、2つのイベントを追加していることは明確にわかります。1つはマウスエンターでもう1つはマウスリーブです。それに対してjQuery版はより簡潔です。jQueryの hoverメソッドは2つのメソッドを受け入れます―1つめのメソッドはマウスエンター用、2つめはマウスリーブ用です。私は個人的にMooToolsのコードのほうが読みやすくて気に入っていますが、これはとても主観的な一つの意見にすぎません。

jQueryはときどき、私の感覚からすると難解すぎるものになることがある、と言っておきたいと思います。一見しただけではメソッドの意味がわからないことがあり、構文を把握するのが難しく感じます。私はMooToolsに密接に親しんでいるのであまりフェアではないのですが、私にはMooToolsのほうが簡単なのです。ただ、私がMooToolsに関して評価していることの一つは、MooToolsのメソッドとクラスの名前はほぼすべて、それそのものを相応しく名指しているということです。メソッドはほとんど常に動詞であり、それが何をするかについて疑念の余地を残しません。プログラミング言語はいつも、いざ書こうとするとドキュメントに当たって文法を探し出すことを求めてくる―と言っているのではありません。そうではなくて、私はMooToolsのAPIがより首尾一貫していて矛盾がないものだと思っているのです。

あなたの好きな方法で

ところで、あなたがjQueryの文法を好きであれば、何が好きでしょうか? MooToolsの実力を例示する方法の一つは、MooToolsの文法をあなた好みのものに変更するのがどれほど簡単なのか、あなたにお見せすることでしょう。もしjQueryのhoverメソッドをMooToolsに実装したいと思ったら、次のように簡単にできるのです:

Element.implement({
    hover : function(enter,leave){
       return this.addEvents({ mouseenter : enter, mouseleave : leave });
    }
});

// そして、jQuery版とまったく同じように使うことができます:
$$('#orderlist li:last').hover(function(){
   this.addClass('green');
},
function(){
   this.removeClass('green');
});

もちろん、まったく同じ事をしてくれるMooToolsプラグインも存在します。これはjQueryの文法でMooToolsを使えるようにしてくれます。MooToolsが拡張性に焦点を合わせているということは、何でもあなたの好きなように実装できることを意味します。これはjQueryにはできないことです。あなたがそう望むなら、MooToolsはjQueryを真似ることができますが、jQueryはMooToolsを真似られません。クラスを書いたり、ネイティブプロトタイプを拡張したり、その他MooToolsが可能なことをしたい場合にも、あなたは自分でそれを書かなければならないでしょう。

デザインパターンとしてのチェーン

Let's do another of these. こういうjQueryのコードがあります(jQueryチュートリアルより):

$(document).ready(function() {
    $('#faq').find('dd').hide().end().find('dt').click(function() {
        $(this).next().slideToggle();
    });
});

これは、私が個人的に好まない文法の例のひとつです。上の例を見ると、このコードが何をしているか確認するのにとても悩まされてしまいます。中でも特に何をしているのかわからないのは、.endが何をしているのかということと、その次に続く.findが、.endが行ったこととどのように関わるのか、という部分です。jQueryのドキュメントを見てみれば.endが行うことはとてもよくわかります(.endは元々のセレクタの値へリセットします。この例では#faqへ戻ります)。でも私の目にはとても奇妙なものに映ります。jQueryを使っていると、あるメソッドがどのような結果を返すのか確信できないことがたびたびあります。jQueryをハッピーに使っている人がたくさんいるところを見ると、この点について他のみんなが困惑していないのは明らかなので、これもまた個人的な好みの問題ということにしておきます。

さあ、同じロジックをMooToolsで見てみましょう:

window.addEvent('domready', function() {
    var faq = $('faq');
    faq.getElements('dd').hide();
    faq.getElements('dt').addEvent('click', function() {
        this.getNext().slide('toggle');
    });
});

ここでもMooToolsのコードは少しばかり冗長ですが、やはりより明確でもあります。また、この例のデザインパターンが#faqへの参照を変数に入れていることにも注目してください。jQueryはこの部分で.endメソッドを使って元の値に戻しています。また、MooToolsでも高度に連続させたコードを書くことは可能であることも付け加えておきたいと思います。例えば:

item.getElements('input[type=checkbox]')
	.filter(function(box) {
		return box.checked != checked;
	})
	.set('checked', checked)
	.getParent()[(checked) ? 'addClass' : 'removeClass']('checked')
	.fireEvent((checked) ? 'check' : 'uncheck');

でも実際のところ、どちらのフレームワークを使う場合でも、このような―domreadyステートメント内にロジックをたくさん詰め込むような―コードを書くことそのものがバッド・プラクティスであると主張しておきます。ロジックを再利用可能な単位にカプセル化するほうがずっと良いことです。

jQueryでコードを再利用する

あるウェブプロジェクトの作業をしているとき、次のようなやり方でコードを書くことはとても魅力的です。DOM要素を選択して「セットアップする」ロジックを、あるページにいくつか追加するだけ。いくつかの要素を見えないようにし、別のいくつかの要素は状態を変え、さらにクリックやマウスオーバー用のイベントリスナーを追加する。こうしたやり方だと、とても効率よく、素早くコードを開発できます。ただ、domreadyステートメントに全ロジックを書くことの問題は、同じことをするコードを異なる場所にたくさん書く結果になるということです。上の例にあったFAQパターンを採用すれば、同じロジックを異なるページのどの場所にでも簡単に適用することができ、用語と定義のどのようなリストも表示できるのです。このパターンを見るたびに同じロジックを繰り返し書きたいと思いますか?

ロジックを再利用可能にするシンプルな方法は、そのロジックを関数内に入れて引数を渡すようにすることです。jQueryだとだいたいこんな感じになるでしょう:

function faq(container, terms, definitions) {
    $(container).find(terms).hide().end().find(definitions).click(function() {
        $(this).next().slideToggle();
    });
};
$(document).ready(function() {
    faq('#faq', 'dd', 'dt');
});

これは、本当に大きくて重要な2つの理由により、とても良い方法です:

  1. 明日もしこのリストの動作方法を変える必要が生じたら(クリック追跡ロジックを追加したいのでログに記録させたくなったり、その定義をAjax経由で持ってきたくなったりするかもしれません)、メインとなるfaqメソッドを変更するだけで、このメソッドを使ったあらゆる場所が即アップデートされます。あるいは、新バージョンのjQueryがリリースされ、動作方法が変わった場合も、色々な場所にあるたくさんのコピーをアップデートするのでなく、ただメソッドを一つアップデートするだけでよくなります。私はこれを、「アプリケーション内で足跡を小さく保つ」こと〔keeping a small footprint in my application〕と呼んでいます。私のアプリケーションが、よりジェネリックなコードに触れるポイントを可能な限り少なく保つことで、バグ修正、フレームワークのアップデート、機能の追加や変更をより容易にできるのです。
  2. 第二の理由は、コードを減らせることです。同じメソッドを何度も繰り返し使うことで、同じことを何度もせずに済みます。このことはあらゆるプログラミング環境において価値あることです。また、私のサイトの訪問者がダウンロードするコードも小さくしてくれます。

実のところjQueryには、このように再利用可能な「ウィジェット」を書くための、もう少し洗練された仕組みがあります。上の例(かなり洗練されていないものです)のようにコードを関数へ落とし込むことを推奨するのでなく、jQueryプラグインを書くことを推奨するものです。だいたい次のような感じです:

jQuery.fn.faq = function(options) {
    var settings = jQuery.extend({
        terms: 'dt',
        definitions: 'dd'
    }, options); 
	// "this" はカレントコンテクストになる。この例ではfaqをレイアウトしたい要素。
    $(this).find(settings.terms).hide().end().find(settings.definitions).click(function() {
        $(this).next().slideToggle();
    });
    return this;
};

こんな風に使います:

$('#faq').faq();

でも上の例を見ると、私たちのfaq関数をこの方法で宣言するのと、これを独立した〔スタンドアローンな〕関数として宣言するのとの間に大きな違いはありません。たしかに、ウィジェット版はグローバル名前空間内に置かれてはいませんが、しかし私たちの例も独自の名前空間内に追加するのは簡単です。それをjQueryに結びつければ、他のjQueryメソッドとつなげて書くことができます。もう一つの利点は、私たちの関数の内側にある "this" が、その時点のjQueryチェーンの内側にある何のカレント・コンテキストにでもなるということです。このパターンをプラグインのために使うことにより、プラグインはjQueryの一部に見えるようになりますが、そのことを除けば基本的に単独の関数となります。この関数はjQueryのカレント・コンテキストを取り、それに対して何かを行って、そのコンテキストをチェーンの中の次のアイテムのために返します。複雑なことはそれほど多くなく、jQueryプラグインを書くことを簡単にしています―ただ関数を1つ書けばよいのです。

ただし、複数のメソッドや状態を持つような、もっと込み入ったjQueryプラグインを書くこともできることを忘れないでください。この種のパターンはjQuery UIプラグインシステムでサポートされており、これはベーシックプラグインと同じメカニズム(faqの例のようなもの)は使用しません。その代わり、複数のメソッドとプロパティを持った一つのオブジェクトをjQueryオブジェクト(すなわち$.ui.tabs)に結びつけるのです。このオブジェクトをinvokeするショートカット($(selector).tabs())があり、これによってfaqプラグインの後にチェーンを継続することができるようになります。しかしこれは、あなたのセレクタ内のアイテム用に作られたtabsオブジェクトへの参照を返さないため、そこに付いているメソッドを呼び出すためには再度そのセレクタを呼び出すことを強制されます。myTabInstance.add(url, label, index)を呼び出す代わりに、あなたはセレクタをもう一度実行し、あなたの関数を名前で(文字列として)呼び出さなければなりません: $(selector).tabs('add', url, label, index);。つまり、あなたは自分のセレクタを2回実行している(どこかでそれを変数内に入れていない限り)ことを意味します。そして、あなたは "add" メソッドへのポインタをまったく持っていません。 "add" メソッドがあればbindやdelayのようなことができるのに。この記事はMooToolsとjQueryのコアに焦点を合わせており、jQueryのUIシステムならこの機能が提供されるのですが、デフォルトのjQueryにそれが付いてくるわけではありません。

MooToolsでコードを再利用する

MooToolsでパターンを定義したいとき、あなたがよく使うことになるのは、Classか、ネイティブオブジェクト(例えばString)にメソッドを実装するかのいずれかでしょう。

MooToolsは、JavaScriptのネイティブスタイルとほぼ完全に異なる言語を提供するのではなく、独自の文法定義とJavaScriptが持つデザインパターンとの中間地点を歩もうと試みます。これを行う方法の一つとして、MooToolsは言語内やDOM内にあるネイティブオブジェクトのプロトタイプを拡張しています。このことはつまり、あなたが文字列をトリミングする必要があるとき、MooToolsはあなたがStringそのものにそのメソッドを追加することを奨励します(ただしMooToolsにはすでにString.trimがあり、あなたが自分で追加する必要はないことに注意してください):

String.implement({
    trim: function() {
        return this.replace(/^\s+|\s+$/g, '');
    }
});

このメソッドは、" no more spaces on the end! ".trim()を実行すると "no more spaces on the end!"が得られることを意味します。ネイティブプロトタイプにプロパティを実装するのは不適切だと言う人もいることでしょう。MooToolsとPrototype.jsが互いにうまく動作しないのはそのせいなのです―ネイティブ型のプロトタイプに手を加えるフレームワークは何であっても、同じことをする他のフレームワークとうまく共演することができません。もし私がString.prototype.foo()を定義し、さらに別のライブラリが同じページで同じメソッドを定義したとすると、後から来たほうが勝つことになります。ある意味で、これはグローバルなwindow名前空間において直面する問題と似ています。これがJavaScriptの動作なのです。JavaScript 1.8はこの方法でたくさんの機能を追加しています。JavaScript 1.8はそれらをプロトタイプに追加しているのです。

MooToolsの開発者は強健なフレームワークをインクルードしており、このフレームワークはあなたが作った機能と協調するよう拡張しやすくなっています。あるページにフレームワークをインクルードする人はそのフレームワークを使い、他のフレームワークは使わないことを〔MooToolsの開発者は〕意図しています。実際、フレームワークを2つダウンロードするようユーザーに頼むのは一種の不作法です。2つのフレームワークをインクルードするただ1つの理由は、両方のフレームワークからプラグインを使いたいからですが、(私自身も含む)MooToolsの開発者は、あなたが選んだフレームワークで利用できないプラグインを求めるなら、あなたは自分の環境にその機能を導入することに時間を使うべきで、あなたのユーザーに別のフレームワークをダウンロードすることを求めるべきではないと考えます。

JavaScriptの動作やネイティブオブジェクトを拡張することの強力さをひとたび学んでしまえば、プログラミングのまったく新しい水準が目の前に広がります。あなたはElementやDateやFunctionを変更することも可能なのです。こんな風にネイティブオブジェクトを拡張することは一種の汚染だという議論もあるでしょうが、私としては、このような使い方こそJavaScriptが運命づけられた道なのだと主張します。これは言語のデザインがもたらす未来〔a design future of the language〕なのです。ネイティブオブジェクトにメソッドを付け加えることで、あなたは自分のコードを簡明で要を得たものにし、また明確に区分けされた状態にすることができるのです。jQueryでも同じことは言えますが、jQueryオブジェクトのプロトタイプを拡張することは制限しています。

jQueryオブジェクトで複数のメソッドコールをつなげる〔チェーンする〕ことは簡単にできますが、他のタイプのオブジェクトではジェネリックを使わなければなりません。例えば、文字列をトリミングしてから1行ごとにイテレートしたい場合、jQueryではこう書かなければいけないでしょう:

$.each( $.trim( $('span.something').html() ).split("\n"), function(i, line){alert(line);});

しかしMooToolsはプロトタイプを修正しているので、こう書くことができます:

$('span.something').get('html').trim().split("\n").each(function(line){alert(line);});

この例を見れば、プロトタイプを修正することがどれだけパワフルであるか、とても明確になります。メソッドチェーンが役に立つ場面は、DOMエレメントに対するチェーンだけではないのです。MooToolsはいかなるオブジェクトでもメソッドをチェーンすることを可能にします。1つのメソッドを複数の要素に一度に実行することもまた可能です。

ここでのカギは、MooToolsフレームワークの核心には「あなたが求めることをプログラムできる場所にしたい」という意志があるということです。コアに存在しない機能があったとすれば、あなたはコアを拡張し、自分の機能を追加することができます。コアの役割とは、誰も求めていない機能を全員に少しずつ提供することではなく、各人が求めていることを自分で書けるツールを提供することなのです。ネイティブオブジェクトのプロトタイプ拡張を容易にし、プロトタイプ型継承の利点を活かしやすくすることで、その目標に大きく近づきます。素朴なJavaScriptでもできることではありますが、MooToolsはそれをより簡単に、より楽しくできるようにしてくれます。

ここでのカギは、MooToolsフレームワークの核心には「あなたが求めることをプログラムできる場所にしたい」という意志があるということなのです。

MooToolsと継承

MooToolsのClass関数は、その名前に反して、実のところクラスではなく、クラスを創り出すこともありません。伝統的なプログラミング言語のクラスを思い起こさせるようなデザインパターンを持ってはいますが、しかし実際のClassでは、オブジェクトとプロトタイプ型継承のことでもちきりなのです。(不運なことに、そうしたことを説明するにも「クラス」のような言葉を使うのが最も便利な方法なのです。この文章ではここまで、私が「クラス」という言葉を使うとき、オブジェクトを返す関数という意味で使っていました。ここからは同じものを「インスタンス」と呼びます。いずれにせよ、それはプロトタイプから継承されてきています)

クラスを作るには、Classコンストラクタにオブジェクトを渡します。こんな風に:

var Human = new Class({
    initialize: function(name, age) {
        this.name = name;
        this.age = age;
    },
    isAlive: true,
    energy: 1,
    eat: function() {
        this.energy = this.energy + 1; // this.energy++ するのと同じ
    }
});

あるオブジェクトをClassに渡すと(上の例では "isAlive" と "eat" というメンバーを持つオブジェクトを渡している)、そのオブジェクトは、そのクラスの全インスタンスのプロトタイプとなり、次のように呼び出すことができます:

var bob = new Human("bob", 20); // bobの名前は "bob" で、20歳

こうしてHumanのインスタンスができました。bobは、私たちがHumanクラスを作ったときに定義したオブジェクトのプロパティを持っています。ここで重要なのは、bobが継承を通じてそれらのプロパティを保持している点です。私たちがbob.eatを参照するとき、bobが実際にこのプロパティを持っているわけではありません。JavaScriptはまずbobを見ますが、彼はeatメソッドを持っていないので、次に継承チェーンを上へさかのぼり、eatメソッドを見つけます。このメソッドは、私たちがHumanクラスを作り出すときに渡したオブジェクトが持っているものです。energyについても同じことです。パッと見ると、このことは潜在的なマズさを抱えているように見えます。私たちは、bobが何か食べた〔eatした〕とき、これから作り出す人間たち〔humans〕全員もエネルギー〔energy〕を得てしまうことを望んではいません。ここで認識しておかなければならない大事なことは、bobのenergyに初めて値を割り当てると、bobに固有の値を割り当てることとなり、以後はプロトタイプを参照しなくなるということです。なので、bobが初めて食べたとき、彼は固有のenergyの定義を得るのです(2がセットされる)。

bob.eat(); //bob.energy == 2

bobの名前(name)と年齢(age)は彼だけがユニークに保持していることを忘れないでください。この2つはinitializeメソッドでクラスが初期化されたときに割り当てられたものです。

このパターン全体は少し奇妙に感じられるかもしれません。しかしここで価値があるのは、私たちは任意のパターンに沿った機能を定義することができ、そして必要な場合にはいつでもそのパターンのインスタンスを作り出すことができる点です。各インスタンスは各自の状態を維持します。なので、別のインスタンスを作るたび、各インスタンスはその他のものと独立しています。が、しかし同じ基礎パターンを継承します。

var Alice = new Human();
//alice.energy == 1
//bob.energy == 2

本当に興味深いのは、この振る舞いをさらに積極的に利用しようとするときです。

Classの拡張と実装

再びjQueryのfaqプラグインに戻りましょう。このプラグインにもっと機能を追加しようとしたら何が起きるでしょうか。質問への回答をサーバから取ってくるようなAjaxバージョンを作りたいとしたらどうしますか? faqプラグインは他の誰かが書いたものだとして、私たちはいかなる方法でもそれ本体を変更しないまま機能を追加したい場合を想像してみましょう。

現実的な選択肢は次のどちらかででしょう。まず、faqプラグインのロジック全体を複製する(思い出してください、あれは1つの関数でした)こと、つまり本質的にはフォークすることになります。あるいは、プラグインを起動してからそれにロジックを付け加えることもできます。この選択を迫られたら、後者を選んでおくほうがトラブルが少なく済みそうです。以下のようなコードになるでしょう:

jQuery.fn.ajaxFaq = function(options) {
    var settings = jQuery.extend({ 
		// リクエスト先のURLなどAjax特有のオプション
        url: '/getfaq.php'
        definitions: 'dd'
    }, options); 
	// "this" はカレントコンテクスト。この場合はfaqレイアウトへと変更したい要素となる
    $(this).find(settings.definitions).click(function() {
        $(this).load(.....); // termをもとにコンテンツをロードするロジック
    });
    this.faq(); // オリジナルのfaqプラグインをコール
});

〔訳注:用語=termをキーとしてサーバへリクエストし、それに対応する定義=definitionをサーバから取得するという動作が想定されている〕

これにはいくつか欠点があります。何よりもまず、faqクラスは定義のためにセレクターを繰り返し使っており、負荷が高まる可能性があります。取得した定義を保存したり、必要なときにそれを使い回す方法は存在しないのです。第二に、私たちのAjaxロジックを、faqプラグインが定義を表示する固有ロジックの中に追加することができません。slideToggleというオリジナルのプラグインは、エフェクトを使って定義を表示(展開)します。私たちのAjaxプラグインのロードが完了する前にこのエフェクトが終了してしまうため、問題をはらんでいます。faqプラグイン全体のロジックを複製することを除いて、この問題を解決する方法はないのです。

では、MooToolsを使ったHumanクラスで考えてみましょう。このクラスはisAliveenergyというプロパティと、eatというメソッドを持っています。プロパティが追加されたHumanの新バージョンを作りたいとしたらどうすればよいでしょう。MooToolsを使って、次のようにクラスを拡張します:

var Ninja = new Class({
    Extends: Human,
    initialize: function(name, age, side) {
        this.side = side;
        this.parent(name, age);
    },
    energy: 100,
    attack: function(target) {
        this.energy = this.energy - 5;
        target.isAlive = false;
    }
});

派生クラスにたくさんの機能を追加しているのがわかると思います。この派生クラスNinjaは、全プロパティをNinja固有のものとして持っています。Ninjaenergyの初期値が100から始まります。Ninjasideプロパティを獲得しています。またattackメソッドで他のHumanを殺すことができますが、その代わりにNinjaのenergyが消費されます。

var bob = new Human('Bob', 25);
var blackNinja = new Ninja('Nin Tendo', 'unknown', 'evil');
//blackNinja.isAlive = true
//blackNinja.name = 'Nin Tendo'
blackNinja.attack(bob);
// bobにチャンスはない

もう少し詳しく見てみると、ここで考えるには興味深いことがあります。Ninjaクラス内にinitializeメソッドを持っていることに注意してください。ということは、このメソッドがHumanクラス内のinitializeメソッドを上書きするように思えるのですが、しかし、私たちはまだこのメソッドにアクセスすることができます。this.parentを呼び出し、親クラスのinitializeが求める引数を渡してやればよいのです。さらに、私たちのロジックが実行されるタイミングを制御することもできます。親クラスのメソッドが呼び出される前や呼び出された後に、子クラスのロジックを実行できるのです。プロパティに(例えばenergyに)新しい値を割り当てることも、新しい機能を割り当てることも可能です。これがjQueryのfaqプラグインで可能だったかどうか考えてみてください。私たちは、まずAjaxをロードし、その後で値をスライドオープンすることしかできませんでした。

MooToolsにはもう一つ、Mixinと呼ばれるパターンを持っています。これは、あるクラスを基にサブクラスへと拡張するという、親から子への関係とは異なるものです。他のクラスへミックスし、別のプロパティを共存させる目的に使うクラスを定義することができるのです。ここに例を示します:

var Warrior = new Class({
    energy: 100,
    kills: 0,
    attack: function(target) {
        target.isAlive = false;
        this.energy = this.energy - 5;
        this.kills++;
    }
});

ここでは、NinjaHumanとは違うものに仕立て上げている特性だけを取り出して、独立したクラスの中に入れ込みました。これでNinjaの外でも特性を再利用できるようになりました。これで、戦士〔warrior〕の特性をNinjaへと浸透させることもできます。このように:

var Ninja = new Class({
    Extends: Human,
    Implements: Warrior, // 2つ以上を実装したいなら配列でもOK
    initialize: function(name, age, side) {
        this.side = side;
        this.parent(name, age);
    }
});

これでNinjaは以前と同じように動作します。しかしWarriorは自由に再利用できるのです:

var Samurai = new Class({
  Extends: Human,
  Implements: Warrior,
  side: 'good'
});

これでSamuraiクラスとNinjaクラスができました。ですが、NinjaSamuraiを定義するのに必要なコードがどれほど少ないか見てください。両クラスは、戦士〔warrior〕の特性を持った人間〔human〕である点は同じですが、サムライはいつも、常に善の側に立ち、対するニンジャは立場を変えられるという点で違いがあります。HumanクラスとWarriorクラスを書くことに時間を使ったおかげで、私たちは3つの異なるクラスを、コードを繰り返さずに得ることができました。しかも、メソッドを呼び出すタイミングやメソッド相互の関連も細かくコントロールできる状態になっています。私たちが作り出した各インスタンスはそれぞれ固有の状態を持ち、コードそのものもとても読みやすいものです。

ここまでで、あなたはMooToolsにおけるクラスの働き方を概観したことになります。ではfaqクラスを見てみましょう。さきほどはjQueryで書きましたが、今度はMooToolsで書き、jQuery版のときと同じく、さらに拡張してAjax機能を追加します。

var FAQ = new Class({
	// OptionsはMooToolsが提供する別のクラス
	Implements: Options,
	// オプションのデフォルト値を設定
	options: {
		terms: 'dt',
		definitions: 'dd'
	},
	initialize: function(container, options) {
		// containerへのリファレンスを格納
		this.container = $(container);
		// setOptionsはOptionをmixinすることで提供されるメソッド
		// 渡されたオプションをデフォルトのものとマージする
		this.setOptions(options);
		// 用語〔terms〕と定義〔definitions〕を格納
		this.terms = this.container.getElements(this.options.terms);
		this.definitions = this.container.getElements(this.options.definitions);
		// attachメソッドを呼び出す
		// これを固有メソッドとして分割したのでクラスを簡単に拡張できる
		this.attach();
	},
	attach: function(){
		// terms全体をループ
		this.terms.each(function(term, index) {
			// 各要素にクリックイベントを追加
			term.addEvent('click', function(){
				// カレントindexに対してtoggleメソッドを呼び出す
				this.toggle(index);
			}, this);
		}, this);
	},
	toggle: function(index){
		// 与えられたindexに対応する定義〔definition〕の開閉状態をトグル
		this.definitions[index].slide('toggle');
	}
});

うわ、コードが多い。全コメントを削除してもまだ24行あります。すでに上で実例を示したように、このプラグインを、jQueryを使って、だいたい同じ量のコードで構築することもできるのでした。ではなぜこのコードはこれほど長くなるのでしょう? そう、よりフレキシブルにしたからです。このクラスを使うには、ただコンストラクタを呼び出せばよいのです、こんな風に:

var myFAQ = new FAQ(myContainer);
// これで、必要ならメソッドを呼び出せる
myFAQ.toggle(2); // 3番目の要素をトグル

インスタンスのメソッドとプロパティにアクセスすることもできます。しかしAjax機能はどうでしょう? jQuery版のAjax拡張部分の問題は、定義部分をオープンするエフェクトを定義がロードされるまで待たせることができないという点です。MooTools版にはこの問題はありません:

FAQ.Ajax = new Class({
	// このクラスはFAQのプロパティを継承
	Extends: FAQ,
	// さらに新たなオプションも追加
	// URL用のもので、用語のインデックスに追加する
	// 実用ではもっとたくさんオプションが付くかもしれないが
	// この例ではこれで充分
	options: {
		url: null;
	},
	// 結果をキャッシュするので、あるセクションが2度開かれた場合
	// サーバにデータをリクエストしない
	indexesLoaded: [],
	toggle: function(index){
		// もし定義をすでにロードしている場合
		if (this.indexesLoaded[index]) {
			// 前バージョンのトグルを呼び出すだけ
			this.parent(index);
		} else {
			// 他の場合、サーバへデータをリクエスト
			new Request.HTML({
				update: this.definitions[index],
				url: this.options.url + index,
				// そして、データがロードされたら定義を展開
				onComplete: function(){
					this.indexesLoaded[index] = true;
					this.definitions[index].slide('toggle');
				}.bind(this)
			}).send();
		}
	}
});

さて、これでサーバから定義を取得できるバージョンのFAQクラスができました。私たちは、サーバからコンテンツが返されたまで定義の展開表示を待機するという新しいロジック(jQuery版ではできませんでした)を統合できたことを忘れないでください。また、本当に新しい機能部分(Ajax機能)とその他少しだけを記述すればよかった〔訳注:=以前のコードを反復する必要はなかった〕ことも覚えておいてください。この拡張性のおかげで、提供する細部機能が微妙に異なるプラグインファミリーを創り出すことも可能となります。また、他の人のプラグインを使いながら、ごく一部だけを自分に必要なかたちへ変更することも(コードをフォークすることなく)可能です。このことは、よくあるデザインのパターン(デート・ピッカー、タブインターフェースなど)が、なぜMooToolsプラグインでは2~3個しか見つからないのかを説明する理由となります。ほとんどのプラグインは、あなたの問題を直接に解決してくれるからであり、あるいは解決されない場合であっても、あなたはすぐそれを拡張して必要な機能を追加できるからなのです。

前に実例を示しましたが、メソッドと状態を使って複雑なjQueryメソッドを書くことも可能です。それを実現する際、DOMとは関わりのないロジックを表現する必要があれば、書くコードの大半は素朴なJavaScriptとなるはずです。しかしjQueryのモデルは、これらのインスタンスを拡張するシステムを提供していませんし、簡単に再利用できるMixinの助けもありません。最終的には、jQueryのプラグインは常にDOMエレメントに接続されます。例えば、URLを処理するクラスを書きたい場合でも、状態を持ったシステムは存在せず、自分で書くしかないのです。

決断の時

jQueryが焦点を合わせているのは、豊かな表現力、素早くて簡易なコーディング、そしてDOMです。それに対してMooToolsは、拡張性、継承、可読性、再利用、容易なメンテナンスに焦点を合わせています。天秤の両側にそれぞれを置いてみると、jQuery側は、簡単にスタートできて結果もすぐに得られるが(私の経験では)再利用しづらいコードになりがちである(ただしこれはあなた次第であって、すぐにjQueryの問題とは言えませんが)とまとめることができます。他方、MooTools側は、学ぶのに時間がかかり、結果を見るまでにたくさんコードを書くこともが必要だが、書き終えた後はより再利用しやすくメンテナンスしやすいものになる、とまとめられます。

さらに言うと、MooToolsコアはあなたが想像するようないかなる機能も含んでおらず、それはjQueryコアでも同じことです。両フレームワークはコアを簡潔な状態に保っており、あなたや他の人々がプラグインや拡張を書く余地を残しています。コアの役割とは、ユーザーが求めそうなあらゆる機能を提供することではなく、ツールを提供することにあります。そのため、ユーザーは想像しうるいかなる機能も実装することができるのです。これはJavaScriptのパワーであり、JavaScriptフレームワークが一般に持つパワーでもあり、そして両フレームワークは特にその点で優れています。MooToolsはより全体論的なアプローチを採用し、DOMの範囲に限らずあらゆる機能を書けるツールを提供しますが、その代償として学習曲線が上昇しにくいものとなっています。MooToolsの、拡張しやすく全体論的なアプローチは、jQueryの機能の上位セット〔superset〕を提供します。しかし、jQueryがわかりやすいDOM APIに焦点を置いていることは、JavaScriptのネイティブオブジェクトから継承したメソッドを使ったり、MooToolsのようなクラスシステムを使うことを(もし望むなら)妨げるわけではありません。

両フレームワークとも素晴らしい選択であると言う理由はそういうことです。私がここで努力してきたのは、2つのコードベースが持つ哲学の違いを明確にするにすることであり、また両者の長所と短所を明確にすることでした。自分のMooToolsに対する思い入れをうまく抑え込めたかどうか疑わしいですが、あなたの役に立つことを願っています。どちらのフレームワークを選ぶとしても、あなたが両者について以前より多くの知識を得られたことを願います。もし充分に時間があるなら、それぞれを使ってサイトを1つ実装してみることを強く薦めます。そしてあなたが独自に両フレームワークのレビューを書いてくれれば、あなたの視点はきっと、私が見過ごした何かを浮かび上がらせることでしょう。

この文章の履歴はgithubで見られます


私について:私はMooToolsのコントリビューターであり、私のサイトClientcideで、JavaScriptやその他のことに関してブログしたり、MooToolsプラグインをたくさんリリースしたりしています。私はMooTools Essentialsという本やMooToolsオンラインチュートリアルの著者でもあります。サンフランシスコ・ベイエリアのClouderaという企業で働いています。いつでもコンタクトできます


A note on comments here: These comments are moderated. No comments will show up until they are approved. Comments that are not productive (i.e. inflammatory, rude, etc) will not be approved. Similarly, "fan" comments won't be approved either - i.e. no "FrameworkX Rulez! It's better than FrameworkY for realz!" are not constructive comments.