Help us understand the problem. What is going on with this article?

jQueryセレクタの仕組み 〜 JSおくのほそ道 #011

More than 5 years have passed since last update.

こんにちは、ほそ道です。
今回からjQueryを操る際には書かせない「jQueryもとい$変数」にディープに迫ります。

対象バージョン:jQuery-2.1.1
目次はこちら

前提の共有

下記の内容はここから先に進む上での前提とします。

当ブログ内での便宜的な呼び方
- jQueryでアクセス出来る変数の事を「jQuery関数」と呼びます
- jQuery関数の戻り値を「jQueryインスタンス」と呼びます
- jQueryインスタンス[number]でアクセス出来る要素群を「コレクション」と呼びます。

予備知識
- $jQueryは同じものです
- jQueryインスタンスはArrayに見えますが独自のObjectです。

jQuery関数の実行パターン

jQuery関数は第一引数の内容によって、その挙動が大きく変わります。
第一引数ベースで挙動を簡単にまとめました。
第二引数はほぼ省略可能で、ここでは端折ります。詳しく知りたい方は公式APIリファレンスを参照してくださいませ。

No 実行パターン 処理
1 jQuery( 文字列 ) selector文字列から検索されたDOM要素のコレクションを返す
2 jQuery( DOM要素 ) 引数のDOM要素をコレクションに入れて返す
3 jQuery( DOM要素配列 ) 引数のDOM要素配列をコレクションに入れて返す
4 jQuery( オブジェクト ) 引数のオブジェクトをコレクションに入れて返す
5 jQuery( jQueryインスタンス ) 引数のjQueryインスタンスのクローンを返す
6 jQuery( 無し ) 空のコレクションを返す
7 jQuery( HTML文字列 ) 引数の文字列から生成したDOM要素のコレクションを返す
8 jQuery( 関数 ) readyイベントでjQuery関数を引数に取るcallback関数を実行

jQuery関数の挙動(概要編)

では次に、jQuery関数が実行されるとどんな事が起こるんでしょうか。
中では下記のような短いコードが実行されます。

jQuery呼び出しの中
jQuery = function( selector, context ) {
  return new jQuery.fn.init( selector, context );
}
  • jQuery関数が実行されると内部的にjQuery.fn.init関数が呼び出されます。
  • jQuery関数からjQuery.fn.init関数へは同じ引数が渡されます。
  • jQuery.fn.init関数はnewで呼び出されます。よって関数実行時のthisはjQueryインスタンスです。
  • jQuery.fn.init関数の戻り値がjQueryインスタントして呼び出し元に返ります。

それではjQuery.fn.init関数の内側も見ていきます。

jQuery.fn.init関数の挙動(セレクタ文字列編)

上でまとめた実行パターン上、一番複雑な挙動となる実行ケース1の「セレクタ文字列を渡した場合」についてまとめました。

  • セレクタ文字が渡ったときのjQuery.fn.init内部挙動

スクリーンショット 2014-06-14 21.21.37.png

3で分岐が発生していますが、ID検索形式(#xxx)かそれ以外かで分岐します。

解説

それでは図の内容を解説します。
第一引数selectorが文字列だった場合、その内容によって大きく下記の3ケースに分かれます。
- ケース1、HTML文字列 -> 実行パターン7:DOM要素生成
- ケース2、ID検索形式(「#elemid」のような形) -> 実行パターン1:セレクタ文字列
- ケース3、それ以外 -> 実行パターン1:セレクタ文字列

ケース1、HTML文字列の場合

この場合は上でまとめた実行パターン7にあたります。
HTML文字列をDOMとして生成して返しますので、要素検索は行われません。
※このパターンは次回取り上げます。

ケース2、ID検索形式の場合

ネイティブ関数のgetElementByIdにて要素が検索されます。
検索されるよう素数が1つですのでこうした方が処理コストが良いという訳ですね。
結果はインスタンスの「0」という要素に設定されます。
配列っぽくinstance[0]とアクセスできるはこの為です。

ケース3、それ以外の場合

jQueryインスタンス.find関数がコールされ、内部で
jQuery.find( selector, context, results )関数による検索処理とthis.pushStack( elems )関数によるインスタンス生成が行われます。
検索処理については別項で述べますがヒットした要素は配列で戻ります。
インスタンス生成はjQuery.merge関数がコールされ、検索結果を新規インスタンスの「0〜n」という要素に割り当てます。(プロパティと呼んでいいのかちょっとアレですが。。)
ID検索形式と同様、配列っぽくinstance[1]とアクセスできるはこの為です。

セレクタ検索(jQuery.find関数)について

jQuery.findは2ついます。
ひとつは Sizzle というオブジェクト。
もうひとつは組み込みの関数です。

ん、何いってんだ?と思いますよね。

ちゃんと説明しますと、前回、githubのjqueryに取り組みましたが、そこのREADMEを読むとGruntでjqueryをビルドする際にgrunt custom:-sizzleというオプションがありました。

このオプションをつけない状態は Sizzle が検索エンジンとなります。
オプションをつけた場合は組み込み関数が検索エンジンとなります。
じつはこのオプションをつけるとjQueryソースの行数は3000行ちょっとまで減らせます。

Sizzle!?

Sizzleは「CSS selector engine」なのです。
SizzleはjQueryからスピンアウトされた独立した仕組みらしいです。
その詳細についてはjQuery日本語ライブラリ様がまとめていらっしゃいます。
ほそ道的に興味深いのは選択肢として「使わない」ことも出来るという事です。
ぜひともパフォーマンス検証したいところです。

まとめ+ソースコードの場所

いかがでしたでしょうか。
今回はソースコードの追跡結果を備忘録的にまとめました。

githubのjQuery上ではどこに何の処理がはいっているのかをまとめておきます。

処理 ソースコードの場所
jQueryインスタンスの生成元 src/core.js
jQuery.fn.init src/core/init.js
jQueryインスタンス.find src/traversing/findFilter.js
jQueryインスタンス.pushStack src/core.js
jQueryインスタンス.merge src/core.js
セレクター(Sizzle指定) src/selector-sizzle.js
セレクター(組み込み関数) src/selector-native.js
Sizzleソース src/sizzle/dist/sizzle.js

今回は以上です。
DOM要素の読み取りについては理解が深まりましたので
次回は実行パターン7:DOM要素の作成にフォーカスしてみたいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away