こんにちは。ソフトブレーンの松嶋です。
ソフトウェア開発の効率や品質を上げていく中で「ライブラリ」は欠かせない存在ですよね。
ライブラリで提供されている機能は「リファレンス」で説明されているので、実際に開発をする際は、リファレンスを見ながら、必要な機能を必要な手続きで開発していくことが多いと思います。
ただリファレンスを読めばほとんどの仕様を理解し、実装できる反面、実際の「ライブラリの中で行われていること」は読まなくても済んでしまうことが多いと思います。
今回はあえてその中身を読んでみよう、といったお話です。
今回の対象:jQuery
WEB系の開発経験がある方はjQueryはご存知の方が多いかと思います。
「jQueryが何か」を一応簡単に説明をすると、「JavaScriptの処理をより簡易に実行するためのライブラリ」「ブラウザ毎に実装されているJavaScriptの機能の差異を吸収し、ブラウザに依らない実装を実現するためのライブラリ」といったところでしょうか。
公式には「jQuery: The Write Less, Do More, JavaScript Library.」(=少ない記述で、多くを実行できるJavaScriptライブラリ)といった説明もされておりますが、まさに正しくその通りで、
経験上、ブラウザ側で実現したい処理はjQueryで一本書いておけば、IEでもChromeでもきちんと動作することがほとんどですし、
要素の検索もJavaScriptが下記のような記述に対して
document.getElementById('hoge').value;
jQueryであれば下記のように
$('#hoge').val();
と、そこまで複雑な書き方を求められるものでもない(=学習コストが低い)です。
また、アニメーションに関する機能や、Ajaxに関する機能も定義されており、これらのjQueryの機能を用いて、プログラマーがシンプルに実装できるというのもjQueryの強みかと思います。
※逆の説明をすると、jQueryを使わず、素のJavaScriptを実装する際は、ブラウザ毎に実装されている機能が異なるため、ややこしい分岐や実装上の考慮が必要になることや、今のWEBサービスで使われているような要件を実現しようとすると、それなりに長いコードを書く必要がある…といったこともあります。
また、jQueryはscriptタグでファイルを読み込むだけで使用可能になるため、導入自体も非常に簡単です。
今回はjQueryのバージョン3.5.1(https://code.jquery.com/jquery-3.5.1.js)のソースを参考に説明をしていきます。
とりあえずjQueryを読む
といってファイルを開いてみましたが、非圧縮版だと10872行もあるんですね。。
ただ俯瞰的に見て書かれていることは当たり前ですが、ただのJavaScriptですので、ポイントとなるところをいくつかピックアップしていこうと思います。
1.「$('#hoge')」や「jQuery('#hoge')」で要素を検索できる理由
scriptタグでライブラリを読み込むことでjQueryを実行できるようになりますが、まずは、それだけで「なぜ実行できるようになるか」といったところにスポットを当てたいと思います。
まず、scriptタグでsrcにjQueryファイルを指定することで、jQueryに記載されているコードがブラウザ上で読み込めるようになります。
私たちは「jQueryというものを使用している」と思いがちですが、上述したように物理的にはたJavaScriptです。
そのため、ブラウザ上ではただのJavaScriptの外部ファイルと同じように取り扱われます。
JavaScriptが読み込まれ、実行される中で、10864行目付近に下記のような記述を実行します。
if ( typeof noGlobal === "undefined" ) {
window.jQuery = window.$ = jQuery;
}
ここで、グローバル変数であるjQuery変数と$変数にローカル変数のjQuery変数を代入しています。
jQueryで「$('#hoge')」や「jQuery('#hoge')」が使用できるのは上記のグローバル変数の記述があるからなんですね。
では、ここでいう「ローカル変数であるjQuery変数」というものはどこで定義されているかというと、149行目付近に下記の変数があります。
var
version = "3.5.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
};
ここで書かれているjQuery変数はシンプルで、「jQuery.fn.init( selector, context );」を返しているだけです。
さらにこの「jQuery.fn.init( selector, context );」がどこで宣言されているかというと、3133行目あたりに下記のような記述があります。
init = jQuery.fn.init = function( selector, context, root ) {
・・・
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[ 2 ] );
if ( elem ) {
// Inject the element directly into the jQuery object
this[ 0 ] = elem;
this.length = 1;
}
return this;
}
・・・
「// HANDLE: $(#id)」というコメントがありますが、この分岐でようやく「document.getElementById( match[ 2 ] );」という最初に説明した「JavaScript」形式の要素検索の記述が出てきます。
少し長くなりましたが、これが「document.getElementById('hoge')」が実行されて要素が返される、という処理で、「$('#hoge')」や「jQuery('#hoge')」というコードで要素が検索できる理由でした。
2.jQueryがクロスブラウザで使用できる理由
jQueryのソースを見ると、いたるところに下記のように、「Support:~」といった記述、説明が書いてあります。
var isFunction = function isFunction( obj ) {
// Support: Chrome <=57, Firefox <=52
// In some browsers, typeof returns "function" for HTML <object> elements
// (i.e., `typeof document.createElement( "object" ) === "function"`).
// We don't want to classify *any* DOM node as a function.
return typeof obj === "function" && typeof obj.nodeType !== "number";
};
ここがjQueryでクロスブラウザ対応させているポイントになり、この説明によると、「Chromeの57以下、Firefoxの52以下で、typeofでHTMLオブジェクトを判定すると「function」と返ってくる」ということが説明されています。
現在の私のPCにはChromeの84.0.4147.135というバージョンが入っていますが、このブラウザでHTMLオブジェクトをtypeofでチェックすると「Object」が返ってきますので、同じ処理を書いていても、判定結果が「Object」となるのと「function」となるのでは大違いですし、油断すると不具合を生んでしまう原因となってしまいます。
jQueryでは、typeofがfunctionであっても、nodeType が「number」でなかった場合には確実に「functionである」と断定できることから、nodeTypeに対する判定を記載して、「isFunctionの引数が関数であるか否か」を判断できるようにしています。
上記のようなブラウザ毎に異なる挙動をjQueryのライブラリ側で吸収してくれることで、jQueryの利用者はブラウザ毎の仕様を気にしなくても実装できるようになっています。
またこういったライブラリの仕事によって「少ない記述で、多くを実行できる」ポイントにつながっているのかと思っています。
まとめ
私も普段はライブラリまでを読み込むことは少ないのですが、改めて読み込んでみると、
今回のjQueryに関しては「JavaScriptを使用する上で、クロスブラウザ間で気にしなければいけないこと」や「JavaScriptで機能を実現するためにはどのような思考が必要か」といったことが見えてきました。
またそこから、言語の特性なども一歩踏み込んで理解できたのではないかと思います。
また、ライブラリはその言語に携わっている様々な人の観点が組み込まれているため、「この言語はどのように書くのが良いか」といった点でも非常にわかりやすくまとまっているものになっていることが多いかと思います。
そういった意味でも言語を学ぶ一つの手段として、ライブラリを読むというのもありかもしれないなと思いました。