ホームページ ウェブフロントエンド jsチュートリアル jQueryセレクタのソースコード解釈(5):tokenize_jqueryの解析処理

jQueryセレクタのソースコード解釈(5):tokenize_jqueryの解析処理

May 16, 2016 pm 04:06 PM
jquery ソースコードの解釈 セレクタ

次の分析は、jQuery-1.10.2.js バージョンに基づいています。

以下では $("div:not(.class:contain('span')):eq(3)") を例として、解析を完了するためにトークン化コードと preFilter コードがどのように調整されるかを説明します。 tokenize メソッドと preFilter クラスのコードの各行の詳細な説明を知りたい場合は、次の 2 つの記事を参照してください。

http://www.jb51.net/article/63155.htm
http://www.jb51.net/article/63163.htm

以下は tokenize メソッドのソース コードです。わかりやすくするために、キャッシュ、カンマ マッチング、リレーショナル文字マッチングに関連するコードをすべて削除し、現在の例に関連するコア コードのみを残しています。削除されたコードは非常に単純です。必要に応じて、上記の記事を参照してください。

また、コードは説明文の上に書かれています。

コードをコピー コードは次のとおりです:

関数 tokenize(selector, parseOnly) {
var matched、match、tokens、type、soFar、groups、preFilters;

これまで = セレクター;
グループ = [];
preFilters = Expr.preFilter;

その間 (これまで) {
if (!matched) {
groups.push(トークン = []);
}

一致 = false;

for (Expr.filter に入力) {
If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[タイプ] || (match = preFilters[タイプ]
(一致)))) {
一致 = match.shift();
tokens.push({
値: 一致、
タイプ: タイプ、
一致: match
});
SoFar = soFar.slice(matched.length);
}
}

if (!matched) {
休憩;
}
}

return parseOnly ? soFar.length : soFar.error(selector) :
tokenCache(セレクター、グループ).slice(0);
}


まず、jQuery の実行中に select メソッドによって初めて tokenize が呼び出され、「div:not(.class:contain('span')):eq(3)」がセレクター パラメーターとしてメソッドに渡されます。
コードをコピー コードは次のとおりです:

これまで = セレクター;

これまで = "div:not(.class:contain('span')):eq(3)"
初めて while ループに入ると、matched には値が割り当てられていないため、if 内の次のステートメント本体が実行され、トークン変数が初期化され、トークンがグループ配列にプッシュされます。

コードをコピー コードは次のとおりです:

groups.push(トークン = []);
その後、for文を入力します。
最初の for ループ: Expr.filter から最初の要素「TAG」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。


コードをコピー コードは次のとおりです:
If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[タイプ] || (match = preFilters[タイプ]
(一致)))) {

match = matchExpr[type].exec(soFar) の実行結果は次のとおりです。

一致 =["div", "div"]

例の最初のセレクターは div で、matchExpr["TAG"] の正規表現に一致しますが、preFilters["TAG"] が存在しないため、if 内のステートメント本体が実行されます。


コードをコピー コードは次のとおりです:
一致 = match.shift();

一致した最初の要素 div を削除し、その要素を一致した変数に代入します。このとき、matched="div", match = ["div"]。

コードをコピー コードは次のとおりです:

tokens.push({
値: 一致、
タイプ: タイプ、
一致: match
}

新しいオブジェクト { value: "div"、type: "TAG"、matches: ["div"] } を作成し、そのオブジェクトをトークン配列にプッシュします。

コードをコピー コードは次のとおりです:

SoFar = soFar.slice(matched.length);

soFar 変数は div を削除します。このとき、soFar=":not(.class:contain('span')):eq(3)"
2 番目の for ループ: Expr.filter から 2 番目の要素「CLASS」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。

コードをコピーします コードは次のとおりです:

If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[タイプ] || (match = preFilters[タイプ]
(一致)))) {

現在の soFar=":not(.class:contain('span')):eq(3)" は CLASS 型の正規表現と一致しないため、このループは終了します。
3 番目の for ループ: Expr.filter から 3 番目の要素「ATTR」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。
同様に、現在残っているセレクターは属性セレクターではないため、このサイクルは終了します。

4 番目の for ループ: Expr.filter から 4 番目の要素「CHILD」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。
同様に、現在残っているセレクターは CHILD セレクターではないため、このサイクルは終了します。

5 番目の for ループ: Expr.filter から 5 番目の要素「PSEUDO」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。

コードをコピー コードは次のとおりです:

If ((match = matchExpr[type].exec(soFar))
&& (!preFilters[タイプ] || (match = preFilters[タイプ]
(一致)))) {

match = matchExpr[type].exec(soFar) の実行結果は次のとおりです。
[":not(.class:contain('span')):eq(3)", "not", ".class:contain('span')):eq(3", 未定義, 未定義, 未定義, 未定義、未定義、未定義、未定義、未定義]

preFilters["PSEUDO"] が存在するため、次のコードが実行されます:

コードをコピー コードは次のとおりです:

match = preFilters[type](match)

preFilters["PSEUDO"] コードは次のとおりです:

コードをコピーします コードは次のとおりです:

"PSEUDO" : function(match) {
var extra、引用符なし = !match[5] && match[2];

if (matchExpr["CHILD"].test(match[0])) {
null を返す;
}

if (match[3] && match[4] !== 未定義) {
一致[2] = 一致[4];
} else if (引用符なし
&& rpseudo.test(引用符なし)
&& (excess = tokenize(unquoted, true))
&& (過剰 = unquoted.indexOf(")", unquoted.length
- 過剰)
- unquoted.length)) {

match[0] = match[0].slice(0, 過剰);
match[2] = unquoted.slice(0, 過剰);
}

return match.slice(0, 3);
}

渡された一致パラメータは次と同じです:

コードをコピー コードは次のとおりです:

[":not(.class:contain('span')):eq(3)", "not", ".class:contain('span')):eq(3", 未定義, 未定義, 未定義, 未定義、未定義

コードをコピーします コードは次のとおりです:

引用符なし = !match[5] && match[2]

引用なし = ".class:contain('span')):eq(3"

コードをコピーします コードは次のとおりです:

if (matchExpr["CHILD"].test(match[0])) {
null を返します。 }

match[0] = ":not(.class:contain('span')):eq(3)"、matchExpr["CHILD"] 正規表現に一致せず、return null ステートメントは実行されません。


コードをコピー コードは次のとおりです:
if (match[3] && match[4] !== 未定義) {
一致[2] = 一致[4]
; }

match[3] と match[4] はどちらも未定義に等しいため、else 文本体が実行されます。

コードをコピーします コードは次のとおりです:
else if (引用符なし
&& rpseudo.test(unquoted)
&& (excess = tokenize(unquoted, true))
&& (超過 = unquoted.indexOf(")", unquoted.length - 超過) - unquoted.length)

このとき、unquoted = ".class:contain('span')):eq(3" が true となり、unquoted contains:contain('span') が正規表現 rpseudo に一致するので、rpseudo となります。 test(unquoted) が true の場合、次のように tokenize を再度呼び出して、引用符なしで再度解析します。


extra = tokenize(unquoted, true)


今回 tokenize 関数を呼び出すとき、受信セレクター パラメーターは ".class:contain('span')):eq(3" に等しく、parseOnly は true に等しくなります。関数本体の実行プロセスは次のとおりです。以下のように:

コードをコピーします コードは次のとおりです:
これまで = セレクター


これまで = ".class:contain('span')):eq(3" 初めて while ループに入ると、matched には値が割り当てられていないため、if 内の次のステートメント本体が実行され、トークン変数が初期化され、トークンがグループ配列にプッシュされます。



groups.push(トークン = []);


の後にfor文を入力します。
最初の for ループ: Expr.filter から最初の要素「TAG」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。


コードをコピー コードは次のとおりです: if ((match = matchExpr[type].exec(soFar))
&& (!preFilters[type] || (match = preFilters[type]
(一致)))) {



現在残っているセレクターはTAGセレクターではないため、このサイクルは終了します。
2 番目の for ループ: Expr.filter から 2 番目の要素「CLASS」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。

match = matchExpr[type].exec(soFar) の実行結果は次のとおりです。

一致 = ["クラス" , "クラス"]

preFilters["CLASS"]が存在しないため、if内の文本体が実行されます。


コードをコピー コードは次のとおりです: 一致 = match.shift();

match の最初の要素クラスを削除し、その要素を matched="class", match = ["class"]
に代入します。

コードをコピーします

コードは次のとおりです: tokens.push({ 値: 一致、
タイプ: タイプ、
一致 : 一致
}

新しいオブジェクト { value: "class"、type: "CLASS"、matches: ["class"] } を作成し、そのオブジェクトをトークン配列にプッシュします。

コードをコピー コードは次のとおりです:

soFar = soFar.slice(matched.length);
このとき、soFar 変数はクラスを削除します。soFar = ":contain('span')):eq(3"

3 番目の for ループ: Expr.filter から 3 番目の要素「ATTR」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。
同様に、現在残っているセレクターは属性セレクターではないため、このサイクルは終了します。

4 番目の for ループ: Expr.filter から 4 番目の要素「CHILD」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。

同様に、現在残っているセレクターは CHILD セレクターではないため、このサイクルは終了します。

5 番目の for ループ: Expr.filter から 5 番目の要素「PSEUDO」を取得し、それを type 変数に割り当て、ループ本体のコードを実行します。

コードをコピーします コードは次のとおりです:
if ((match = matchExpr[type].exec(soFar))
&& (!preFilters[type] || (match = preFilters[type]
(一致)))) {

match = matchExpr[type].exec(soFar) の実行結果は以下の通りです:

[":contain('span')", "contain", "'span'", "'", "span", 未定義, 未定義, 未定義, 未定義, 未定義, 未定義]

preFilters["PSEUDO"] が存在するため、次のコードが実行されます:


コードをコピー コードは次のとおりです:
match = preFilters[type](match)

preFilters["PSEUDO"] コードは上に示されているため、ここではリストされません。

コードをコピーします コードは次のとおりです:
"PSEUDO" : function(match) {
var 過剰、引用符なし = !match[5] && match[2];
If (matchExpr["CHILD"].test(match[0])) {
null を返す; }

If (一致[3] && 一致[4] !== 未定義) {
一致[2] = 一致[4];
} else if (引用符なし
                                                                                                                                                                                                      && (excess = tokenize(unquoted, true)) && (excess = unquoted.indexOf(")", unquoted.length
- 過剰)
- unquoted.length)) {

match[0] = match[0].slice(0, 過剰)
match[2] = unquoted.slice(0, 過剰)
}

match.slice(0, 3) を返します。 }



受信一致パラメータは次と同じです:
[":contain('span')", "contain", "'span'", "'", "span", 未定義, 未定義, 未定義, 未定義, 未定義, 未定義]


コードをコピーします

コードは次のとおりです: 引用符なし = !match[5] && match[2]; 引用符なし = "スパン"


コードをコピー


コードは次のとおりです:

if (matchExpr["CHILD"].test(match[0])) { null を返す; }

「:contain('span')」は matchExpr["CHILD"] 正規表現と一致しないため、内部ステートメント本体は実行されません。

コードをコピー コードは次のとおりです:

if (一致[3] && 一致[4] !== 未定義) {
一致[2] = 一致[4];
}

match[3] = "'" かつ match[4] ="span" なので、内部の if 文本体が実行され、match[2] に "span" が代入されます

コードをコピーします コードは次のとおりです:

match.slice(0, 3) を返します。
一致の最初の 3 つの要素のコピーを返します

このとき、tokenizeメソッドのforループに戻って実行を継続します。このときの各変数の値は以下の通りです。
一致 = [":contain('span')", "contain", "span"]

これまで = ":contain('span')):eq(3"

コードをコピーします コードは次のとおりです:
一致 = match.shift();


一致配列から「:contain('span')」を削除し、一致した変数に割り当てます

コードをコピーします コードは次のとおりです: tokens.push({
値: 一致、
タイプ: タイプ、
一致 : 一致
}



新しいオブジェクトを作成します { 値: ":contain('span')"、type:"PSEUDO"、一致: ["contain", "span"] }、オブジェクトをトークン配列にプッシュします。




コードをコピー コードは次のとおりです: soFar = soFar.slice(matched.length);

soFar変数は「:contain('span')」を削除し、その後、forループが終了して再度whileループが実行されるまで、soFar="):eq(3)"となります。有効なセレクターがないため、while ループを終了します。


コードをコピー

コードは次のとおりです: parseOnly を返す : soFar.error(セレクター) : tokenCache(セレクター、グループ).slice(0);

このとき parseOnly = true なので、この時点の soFar の長さ 6 が返され、preFilters["PSEUDO"] のコードが実行され続けます

コードをコピー

コードは次のとおりです: else if (引用符なし && rpseudo.test(unquoted) && (excess = tokenize(unquoted, true))
&& (超過 = unquoted.indexOf(")", unquoted.length - 超過) - unquoted.length)



余分な変数に 6 を代入し、コード

コードをコピー

計算: セレクターの終了位置 (つまり、右括弧の位置) ではありません 22

コードをコピー

完全な :not セレクター文字列 (match[0]) とその括弧内の文字列 (match[2]) をそれぞれ計算します。これらは次と同等です:

match[0] = ":not(.class:contain('span'))"

match[2] = ".class:contain('span')"

コードをコピー


コードは次のとおりです:

match.slice(0, 3) を返します。

一致する最初の 3 つの要素のコピーを返します。
トークン化関数に戻り、match = [":not(.class:contain('span'))", "not", ".class:contain('span')"]

コードをコピー コードは次のとおりです:

一致 = match.shift();
match の最初の要素「:not(.class:contain('span'))」を削除し、その要素を一致した変数に代入します。このとき、matched="":not(.class:contain( ')スパン'))"",

match = ["not", ".class:contain('span')"]

コードをコピー コードは次のとおりです:
tokens.push({
値: 一致、
タイプ: タイプ、
一致 : 一致
}

新しいオブジェクトを作成します { 値: ":not(.class:contain('span'))""、タイプ: "PSEUDO"、一致: ["not", ".class:contain('span') "] } を実行し、オブジェクトをトークン配列にプッシュします。このとき、トークンには 2 つの要素があります。つまり、selector ではなく div です。


コードをコピー コードは次のとおりです:
soFar = soFar.slice(matched.length);

SoFar変数は「:not(.class:contain('span'))」を削除します。このとき、soFar=":eq(3)"は、このforループを終了した後、再びwhileループに戻ります。同様に、トークンの 3 番目の要素の eq セレクターを取得するプロセスは not と一致するため、ここでは詳しく説明しません。最終グループの結果は以下の通りです: group[0][0] = {値: "div"、タイプ: "TAG"、一致: ["div"] }


group[0][1] = {値: ":not(.class:contain('span'))"、タイプ: "PSEUDO"、一致: ["not"、".class:contain('スパン')"] }

グループ[0][2] = {値: ":eq(3)"、タイプ: "PSEUDO"、一致: ["eq", "3"] }


parseOnly を返す : soFar.error(セレクター) :
tokenCache(セレクター、グループ).slice(0);


parseOnly = 未定義のため、tokenCache(selector, groups).slice(0) が実行され、グループがキャッシュにプッシュされ、そのコピーが返されます。
これで、すべての解析が完了したのではないかと疑問に思う人もいるかもしれません。はい、実際の操作ではこれを再度解析する必要があります。もちろん、「class:contain('span')):eq(3」を解析したときに、有効なセレクターの結果をキャッシュに保存できれば、再度解析する必要がなくなり、実行速度が向上します。実行中に「.class:contain('span')」が分析のために再度送信されると、キャッシュに保存されるため、現在の実行速度が向上するだけです。 この時点で、実行プロセス全体が終了しました。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

jQueryのリファレンスメソッドを詳しく解説:クイックスタートガイド jQueryのリファレンスメソッドを詳しく解説:クイックスタートガイド Feb 27, 2024 pm 06:45 PM

jQuery 参照方法の詳細説明: クイック スタート ガイド jQuery は、Web サイト開発で広く使用されている人気のある JavaScript ライブラリであり、JavaScript プログラミングを簡素化し、開発者に豊富な機能を提供します。この記事では、jQuery の参照方法を詳しく紹介し、読者がすぐに使い始めるのに役立つ具体的なコード例を示します。 jQuery の導入 まず、HTML ファイルに jQuery ライブラリを導入する必要があります。 CDN リンクを通じて導入することも、ダウンロードすることもできます

jQueryでPUTリクエストメソッドを使用するにはどうすればよいですか? jQueryでPUTリクエストメソッドを使用するにはどうすればよいですか? Feb 28, 2024 pm 03:12 PM

jQueryでPUTリクエストメソッドを使用するにはどうすればよいですか? jQuery で PUT リクエストを送信する方法は、他のタイプのリクエストを送信する方法と似ていますが、いくつかの詳細とパラメータ設定に注意する必要があります。 PUT リクエストは通常​​、データベース内のデータの更新やサーバー上のファイルの更新など、リソースを更新するために使用されます。以下は、jQuery の PUT リクエスト メソッドを使用した具体的なコード例です。まず、jQuery ライブラリ ファイルが含まれていることを確認してから、$.ajax({u

jQueryで要素の高さ属性を削除するにはどうすればよいですか? jQueryで要素の高さ属性を削除するにはどうすればよいですか? Feb 28, 2024 am 08:39 AM

jQueryで要素の高さ属性を削除するにはどうすればよいですか?フロントエンド開発では、要素の高さ属性を操作する必要が生じることがよくあります。要素の高さを動的に変更する必要がある場合や、要素の高さ属性を削除する必要がある場合があります。この記事では、jQuery を使用して要素の高さ属性を削除する方法と、具体的なコード例を紹介します。 jQuery を使用して高さ属性を操作する前に、まず CSS の高さ属性を理解する必要があります。 height 属性は要素の高さを設定するために使用されます

jQuery のヒント: ページ上のすべての a タグのテキストをすばやく変更する jQuery のヒント: ページ上のすべての a タグのテキストをすばやく変更する Feb 28, 2024 pm 09:06 PM

タイトル: jQuery ヒント: ページ上のすべての a タグのテキストをすばやく変更する Web 開発では、ページ上の要素を変更したり操作したりする必要がよくあります。 jQuery を使用する場合、ページ内のすべての a タグのテキスト コンテンツを一度に変更する必要がある場合があります。これにより、時間と労力を節約できます。以下では、jQuery を使用してページ上のすべての a タグのテキストをすばやく変更する方法と、具体的なコード例を紹介します。まず、jQuery ライブラリ ファイルを導入し、次のコードがページに導入されていることを確認する必要があります: &lt

jQuery を使用してすべての a タグのテキスト コンテンツを変更する jQuery を使用してすべての a タグのテキスト コンテンツを変更する Feb 28, 2024 pm 05:42 PM

タイトル: jQuery を使用して、すべての a タグのテキスト コンテンツを変更します。 jQuery は、DOM 操作を処理するために広く使用されている人気のある JavaScript ライブラリです。 Web 開発では、ページ上のリンク タグ (タグ) のテキスト コンテンツを変更する必要が生じることがよくあります。この記事では、この目標を達成するために jQuery を使用する方法を説明し、具体的なコード例を示します。まず、jQuery ライブラリをページに導入する必要があります。 HTML ファイルに次のコードを追加します。

jQuery における eq の役割と応用シナリオを理解する jQuery における eq の役割と応用シナリオを理解する Feb 28, 2024 pm 01:15 PM

jQuery は、Web ページでの DOM 操作やイベント処理を処理するために広く使用されている人気のある JavaScript ライブラリです。 jQueryではeq()メソッドを利用して指定したインデックス位置の要素を選択しますが、具体的な使い方と応用シーンは以下の通りです。 jQuery では、 eq() メソッドは、指定されたインデックス位置にある要素を選択します。インデックス位置は 0 からカウントされます。つまり、最初の要素のインデックスは 0、2 番目の要素のインデックスは 1 などとなります。 eq() メソッドの構文は次のとおりです。 $("s

jQuery 要素に特定の属性があるかどうかを確認するにはどうすればよいですか? jQuery 要素に特定の属性があるかどうかを確認するにはどうすればよいですか? Feb 29, 2024 am 09:03 AM

jQuery 要素に特定の属性があるかどうかを確認するにはどうすればよいですか? jQuery を使用して DOM 要素を操作する場合、要素に特定の属性があるかどうかを判断する必要がある状況がよく発生します。この場合、jQuery が提供するメソッドを使用してこの関数を簡単に実装できます。以下では、jQuery 要素が特定の属性を持つかどうかを判断するために一般的に使用される 2 つの方法を紹介し、具体的なコード例を添付します。方法 1: attr() メソッドと typeof 演算子 // を使用して、要素に特定の属性があるかどうかを判断します

jQueryを使用してテーブルに新しい行を追加する方法の紹介 jQueryを使用してテーブルに新しい行を追加する方法の紹介 Feb 29, 2024 am 08:12 AM

jQuery は、Web 開発で広く使用されている人気の JavaScript ライブラリです。 Web 開発中は、JavaScript を使用してテーブルに新しい行を動的に追加することが必要になることがよくあります。この記事では、jQuery を使用してテーブルに新しい行を追加する方法を紹介し、具体的なコード例を示します。まず、jQuery ライブラリを HTML ページに導入する必要があります。 jQuery ライブラリは、次のコードを通じてタグに導入できます。

See all articles