05 | 2017/06 |  07

  1. 無料サーバー

User forum-FC2BLOG-Info-Edit Template-Post-Edit-Upload-LogOut

CSSやJavascript自習の苦闘史を綴っていきたい。恐縮ですがJavascriptを有効にしてご覧ください。
2005年12月から社会問題も掲載!

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

 

jQuery() の挙動を解読する(1) インスタンスの初期化:init() upon Ver1.3.2──jQuery解読(5)

  • 初稿:2007/10/31
  • 改訂:2007/11/19……thisに関する記述追加、用語の統一化
  • 再改訂:2007/11/23……何カ所かの基礎的なミスを修正
  • 再改訂:2007/12/3……表現等を抜本的に見直した
  • 再改訂:2009/2/22……Ver1.3.2 対応に改訂

init()メソッドの概要解読

このエントリイでは、init コンストラクタによるインスタンスの初期化過程について概要解読を行います。

jquery.js のインクルード完了時には、直ぐにコード全体を包含する無名関数が起動され、インスタンスオブジェクトが作成され、その初期化を int() メソッドが担います。

まず該当箇所のコードを抜粋すると以下の通りです。 ( 行数はVer1.3.2による )

24: jQuery = window.jQuery = window.$ = function( selector, context ) {
25:  // The jQuery object is actually just the init constructor 'enhanced'
26:  return new jQuery.fn.init( selector, context );
27: },
28:
29: // A simple way to check for HTML strings or ID strings
30: // (both of which we optimize for)
31: quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
32: // Is it a simple selector
33: isSimple = /^.[^:#\[\.,]*$/;
34:
35: jQuery.fn = jQuery.prototype = {
36: init: function( selector, context ) {
37: // Make sure that a selection was provided$
38:  selector = selector || document;
39: 
40:  // Handle $(DOMElement)
41:  if ( selector.nodeType ) {
42:   this[0] = selector;
43:   this.length = 1;
44:   this.context = selector;
45:   return this;
46:  }
47:  // Handle HTML strings
48:  if ( typeof selector === "string" ) {
49:   // Are we dealing with HTML string or an ID?
50:   var match = quickExpr.exec( selector );
51: 
52:   // Verify a match, and that no context was specified for #id
53:   if ( match && (match[1] || !context) ) {
54: 
55:    // HANDLE: $(html) -> $(array)
56:    if ( match[1] )
57:     selector = jQuery.clean( [ match[1] ], context );
58: 
59:    // HANDLE: $("#id")
60:    else {
61:     var elem = document.getElementById( match[3] );
62: 
63:     // Handle the case where IE and Opera return items
64:     // by name instead of ID
65:     if ( elem && elem.id != match[3] )
66:      return jQuery().find( selector );
67: 
68:     // Otherwise, we inject the element directly into the jQuery object
69:     var ret = jQuery( elem || [] );
70:     ret.context = document;
71:     ret.selector = selector;
72:     return ret;
73:    }
74: 
75:   // HANDLE: $(expr, [context])
76:   // (which is just equivalent to: $(content).find(expr)
77:   } else
78:    return jQuery( context ).find( selector );
79: 
80:  // HANDLE: $(function)
81:  // Shortcut for document ready
82:  } else if ( jQuery.isFunction( selector ) )
83:   return jQuery( document ).ready( selector );
84: 
85:  // Make sure that old selector state is passed along
86:  if ( selector.selector && selector.context ) {
87:   this.selector = selector.selector;
88:   this.context = selector.context;
89:  }
90: 
91:  return this.setArray(jQuery.isArray( selector ) ?
92:   selector :
93:   jQuery.makeArray(selector));
94: },
95: 
96: // Start with an empty selector
97: selector: "",

▲ToTop

RegExp.exec()メソッドのための正規表現文字列用意

31行で定義されている変数 quickExpr は引数 selector に対する正規表現検索のための文字列で、その意味は次のようになります。

「先頭が"<"ではないゼロ個以上の文字で始まり、続いて部分一致文字列その1 <の後に部分一致文字列その2 何らかの文字か空白文字 が1文字以上あり、>で終わる文字列 があり、最後に>ではない文字が末尾までゼロ個以上ある文字列

あるいは

行頭が#で始まり、部分一致文字列その3 何らかの単語が1個以上 が行末まである文字列」

のいずれか。

ここに「単語」とは「文字、数字あるいはアンダースコアのいずれかで構成されている文字列」です。なお、部分一致文字列2(何らかの文字か空白文字が1つ以上ある文字列)が以後のコードで呼び出される箇所はまだ「発見」していません。

RegExp.exec() メソッドの解読

重要な点なので敢えてここに記します。

RegExp.exec()メソッドは、正規表現による「汎用的で最も強力な」検索メソッド ( 『Javascriptクイックリファランス Javascript1.5対応』pp.112~113参照 )とされていますが、そのように言わしめる理由は部分一致文字列を取得できるからである、と確信します。

jQueryにおける利用法を基にそれを紐解けば、次のようになります。

quickExpr.exec(selector) の結果はローカル変数 match に格納され、この match は exec() メソッドの仕様上配列となります。そして、当該配列には順に次の情報が格納されます。これらの正規表現を駆使した検索によって、"<・・・>" や "#idName"、".className" が抽出されます。

ローカル変数 match 配列に格納される情報
 match[0]──/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/ なる検索に一致した文字列
 match[1]──/<(.|\s)+>/ なる検索に一致した文字列
 match[2]──/.|\s/ なる検索に一致した文字列
 match[3]──/\w+/ なる検索に一致した文字列

▲ToTop

init( selector,context ) の構成とインクルード時の挙動

さて、35 行以降 530 行まで、延々と jQuery.prototype プロパティの設定が行われますが、jquery.js の全体を包含する無名関数が実行されると、init() メソッドが 26行 から呼び出されます。

呼び出された init() メソッドが最初に行うことは第一引数が与えられているかどうかのチェックです。第一引数があればそれを selector に代入し、なければ document プロパティを selector に代入します(38行)。

ここに引数 selector は jquery.js が読み込まれた時点で 95 行により空文字となっていますので、|| 演算子によって右項が選ばれて document が左辺の selector に代入されます。

続く長いコードは if キーワードによって幾つかの階層に分岐されますが、その構造を視覚化すれば次のようになります。

init()
├(1) selector が DOM Element の場合…………40~46行
│  ex."document","document.myForm.elements","document.anchors[2]"
├(2) selector が文字列型の場合…………47~78行
│ ├(2-1)HTML 形式の場合 ex."<div><p>Hello</p></div>"
│ ├(2-2)"#string"の場合 ex."#example1"
│ │   ├─(2-2-1)IEかOperaにおいてID名の代わりにnameが返された場合
│ │   └─(2-2-2)その他の一般的な場合
│ └(2-3)正規表現検索文字列 quickExpr に合致しない場合
│     ex."div > p"、"*"、"div, span, p.className"、"#idName > *"、
│       "#idName ~ div"、"label + input"、"tr:first"、":header"、
│       "div:has(p)"、"selector1, selector2, ・・・,selectorN"、
│       "tr:even "、"td:gt(index) "、"div:visible "、・・・・
├(3) selectorが関数型の場合……………………………………………80~83行
└(4) 最後の処理……………………………………………………………91~93行

それぞれの場合の return 値は以下のようになります。
 (1-1)  this(インスタンスオブジェクト)
 (2-1)  指定したHTML要素の配列:selector=jQuery.clean(match[1],context)…44行
 (2-2-1) (for IE,Opera Bug):指定した idName 値により検索された要素の配列
      jQuery().find(selector)………………………………………………………53行
 (2-2-2) document.getElementById( match[3] ) による取得値に
      context:document と selector:selector プロパティを付加したオブジェクト
 (2-3)  context と selector を入れ替えて jQuery( context ).find( selector )
      を実行した結果の配列
 (3)   selectorが関数オブジェクトの場合:関数実行待機状態にする。
 (4)   2-1の場合及び 1~3 の 2-1 以外のいずれにも該当しない場合:
      配列 [selector]を返す。
jQuery(selector,context)の様々な具体的コード

それには本家サイトの API Reference が手っ取り早いでしょう。こちら(API/1.2/Core - jQuery JavaScript Library)に簡単な例示が掲載されています。

▲ToTop

init()メソッド起動まで及びinit()メソッド自体の挙動を追跡する

init()メソッドの挙動は結構複雑です。次々と jQuery 固有のメソッドが連鎖的に呼び出されて目的が遂行されます。そこで jQuery.js のインクルード時と全体を包含する無名関数の実行により、init()メソッドが最初に起動される迄の過程を追跡し、特に this がどの様に変化するか、返値は何か、に着目してその挙動をまとめてみました。

まず、jQuery.jsがインクルードされ、その後ユーザー指示による jQuery(a,c) 実行によって、インスタンスが生成される迄の動きです。

タイミング 前this 履行行為 後this 返値
include時 window 変数設定、prototypeプロパティ設定 window なし
jQuery(s,c)実行 window new演算子によるインスタンス生成とjQuery(s,c)コンストラクタ呼び出し new jQuery(s,c)によるインスタンス
(1)new jQuery(c).find(s)の結果値
(2)new jQuery(document).ready(s)の結果値
(3)[s]

上表よりも更に深化させた分析も行ってみました。よろしければ、こちらの Javascript基礎の基礎(1) return 値は「何に」返されるのか?──jQuery解読(16)をご覧ください。 こちら は、表では静的で理解しにくい部分があるため、動きを文章化し、return先迄含めてまとめたものです。(2007/11/27記)

コンストラクタによる初期化=init()メソッドの実行過程

更にインスタンス生成後に行われる初期化過程を追跡してみると、次のようになるはずです。

前this 履行行為 後this 返値
new jQuery(s,c)によるインスタンス jQuery().find(s)実行 jQuery()によるインスタンス jQuery().find(s)の結果値
new jQuery(s,c)によるインスタンス document.getElementById(・・)の実行 インスタンスに左記結果が代入され それが返値となる
new jQuery(s,c)によるインスタンス new jQuery(c).find(s)による新規インスタンスの生成 new jQuery(c)による新規インスタンス jQuery(c).find(s)の結果値
new jQuery(s,c) によるインスタンス new jQuery(document).ready(s)による新規インスタンスの生成 new jQuery(document) によるインスタンス jQuery(document).ready(s)の実行結果値
new jQuery(s,c)によるインスタンス 配列[s]の生成 インスタンスへの配列の代入 その配列

変数 jQuery と this の参照先の変化

一般にthisは、new演算子とコンストラクタから生成されたインスタンスオブジェクトを参照するか、関数を起動したオブジェクトを参照します。ですから、new 演算子によって新たなインスタンスが定義されるその都度 this の参照先は変化します。上表のとおり、thisの参照先はインスタンス作成の度に変化します。またそのインスタンスの挙動の中で起動されたメソッドによって、様々に変化します。

一方、変数 jQuery の参照先は常にコンストラクタ関数オブジェクトのままで、それは固有のクラスプロパティとクラスメソッドを保持し続けます。

ところで、このようなコンストラクタ、インスタンス及び this の振る舞いは、jQuery.js の冒頭部及び jQuery.prototype オブジェクト定義の直後に配置されている、合計6行の次のコードによってもたらされています。

24: jQuery = window.jQuery = window.$ = function( selector, context ) {
25:  // The jQuery object is actually just the init constructor 'enhanced'
26:  return new jQuery.fn.init( selector, context );
27: },
  --------------------------------------------------------
540: // Give the init function the jQuery prototype for later instantiation
541: jQuery.fn.init.prototype = jQuery.fn;

無名関数にコンストラクタの機能を持たせると同時に、そのコンストラクタから生成するインスタンスの初期化機能をも内包させる───こうしたコンストラクタ関数は一般に目にします。しかし、インスタンスの初期化結果をリターンさせると共に、自ら一部ののプロパティの prototype オブジェクトに、自信のプロトタイプオブジェクトを継承させる点、この2点がこのコードの大きな特徴なのではないでしょうか。───僅か6行でこれだけのことを成し遂げているのですから、驚いてしまいます。

▲ToTop

init()メソッド詳説

まず第一に、第一引数 selector が DOM エレメントであれば、コンストラクタにより生成されたインスタンスオブジェクト( 以下 insObj と表記 )のプロパティにそれを格納させて返値としています。(// Handle $(DOMElement) 40~45行 )

第二に selector が文字列型であれば(上の構成図の(1):コードの48~78行)、それを更に分岐するために上述の正規表現検索 quickExpr.exec(selector) が登場し、正規表現検索文字列 quickExpr の exec() メソッドが文字列 selector に適用されます。(50行)

以下 selector が文字列型だった場合の更なる分岐は次項にまとめます。

他方、selectorの型が文字列でない場合には、関数型であるかどうかチェックされ(上の構成図の(2):コードの80~83行)、関数型であれば有名なコード jQuery(document).ready(function(){ /* Your code here*/ }); が呼び出されます。(83行)

最後に文字列型の一部のケースや以上の条件分岐に掛からない場合においては、 selector を値とする配列が返されます。(91-93行)

selector が文字列型の場合の詳細

さて、selector が文字列型の場合の中身を見てみると次のように分岐されます。

上記 RegExp.exec() メソッドの結果が存在し、かつそれが "<tagName>" という文字列があるか、または"#idName"文字列がある場合

タグ名にヒットした場合には、jQuery.clean (<tagName>,context) によってエラーチェックしてから配列を求め(56~57行)、ID名称にヒットした場合には、jQuery (idName) から該当要素を抽出しています。なお IE 及び Opera のバグ対策が 63~66 行で講じられています。

ここに、HTMLタグ名から配列を求めるコードで使用される jQuery.clean クラスメソッドは、誤表記をチェックして valid な文字列にしています。その名の通り文字列の「清掃」を行うわけです。

RegExp.exec() メソッドによる検索結果が存在しない場合
──Sizzle関数オブジェクトの活用

この場合には、selector と contextを入れ替えて、jQuery( context ).find( selector ) を実行させています。(75~78行)この処理は、前半の jQuery( context ) によってcontext に該当する注目対象を抽出し、この関数処理が終わった時点で、当初の第一引数であるselectorを引数とする find ( selector ) メソッドが起動し、注目対象から selector 条件に該当する対象を絞り込んでいます。

ここにおいて、1.3.xバージョンから登場した Sizzle が発動されます。2364 行の jQuery.find = Sizzle; により、jQuery クラスメソッド find を起動すると Sizzle 関数オブジェクトが呼び出される仕様になっているからです。

以上見てきたとおり、jQuery は目的とする要素を抽出するために、そのインスタンスメソッドとクラスメソッドを縦横無尽に活用します。そのためコードは難解であり、複雑怪奇です。しかし、その複雑さが解読の興味深さであるとも言えます。

なお、ここで呼び出されている jQuery の各種インスタンスメソッド・クラスメソッド(cleanメソッド、eachメソッド及びfindメソッド)の解読は別の機会に行うことにします。

▲ToTop

 

■ コメントの投稿 ■

管理者にだけ表示を許可する

●トラックバック●

■トラックバックURLはこちら■
http://hkom.blog1.fc2.com/tb.php/574-6948970a

●参照元一覧●

<provided Fc2>
<provided i2i>

▲ToTop

 90%近いシェアを握っているインターネットエクスプローラの描画エンジンを利用したタブbrowser。沢山のタブbrowserがあるが、多機能、カスタマイズフリー、スクリプト利用等で一日の長がある。Gekkoエンジンへの対応も行われ、IEからの自立独立の方向に向かっている。2005年7月にはIE7が登場する見通しの中で、今後の発展が望まれる。

 多様なCSS作成支援機能を備えた、タグ入力式 HTML&CSS作成支援エディタ。スキンデザインもすっきりしている。テキストエディター上で作成するよりも確実で安全にタグ打ちが出来る。
文字コードを選べないのが欠点。

 StyleNote同様のタグ入力式 HTML&CSS 作成支援エディタ。長年使用してきたが現在StyleNoteに乗り換えつつある。

 クリップボード履歴情報を活用する為のソフト。画像まで履歴を取ってくれるのが嬉しい。このソフトを使わない日は絶対ない程に重宝し、愛用している。

 起動中のウィンドウの「コピーできない」説明文などの文字列を取得し、コピー可能な文字データにするツール。何かと便利。

 ストリーミングデータを保存することが出来るソフト。動画利用には不可欠なソフトだ。

 無料ながらレイヤー機能を有し、スクリプトによる拡張も可能な、sleipnir作者が提供している優れもの画像編集ソフト。

 画面キャプチャソフトと言えばこれに勝るものなし、ではないだろうか? 様々な取得方法を有しており、ブログ作成にもHomepage作成に不可欠だ。Jtrimと並んでWoodyBellsの作品。

 複数ファイルの同時編集は出来ないが、透過pngも作れる画像編集ソフト。
(以下当該サイトから抜粋)初心者にも簡単に操作が出来るフォトレタッチソフトです。多くの加工機能で画像に様々な効果を与えることができます。非常に軽快に動作するため、ストレスなく操作できます。

 Animation Gifファイルを作れる無料ソフト。

 キャプチャソフト。画面内にサイト全体が表示しきれない場合でも、これを使えば全体をキャプチャすることが出来る。

 画像処理。画像のフォーマット変換のみならず、色数やサイズ、圧縮率の変更まで一括処理できてしまう『BatchGOO!』は、大量の画像をまとめて処理したいときに大変便利なソフト。BMP, TIFF, JPEG, PCX, PNG の相互変換をはじめ、色数・サイズ・解像度の統一、JPEG圧縮率の調節など、ホームページ用の画像や携帯電話用の壁紙を揃えるのに抜群の相性を見せる。(Vectorの当該ソフト紹介頁より抜粋引用)

 名前から直ぐに想像が付くように画像のサイズを測るためのソフトだ。Homepage作成には欠かせない。2カラム、3カラムのレイアウトを行う場合に大変重宝する。

 ランチャーソフトは沢山あるが、中でもこれが一押しだ。2年以上使ってきたがその操作性には毎日満足している。これを使い始めてからデスクトップには一切のアイコンを表示することをやめてしまった。

 AdobeReader7によって、起動時間が長すぎるという長年のユーザーの不満はある程度解消した。そのためこの高速化ソフトは存在価値が低下してしまったかもしれない。AdobeReader6迄はこのソフトによる起動高速化で恩恵を受けてきた。

 IE専用が難点だが、様々なサイト内でIDやパスワードを入力するのに重宝するソフト。コンテキストメニューから簡単に起動できるのがGood! sleipnir等のIEの描画エンジンを利用しているブラウザでも使える。

 利用しているパソコンの諸元値を取得するには、このソフトがベストだ。インストール済みソフトの一覧が取得できるのも嬉しい。

 WMPは機能が豊富なだけ重い。RealPlayerも同様だ。そこでMedia Player Classicを使いたい。動作が軽快なだけではなく、対応しているファイル形式もすこぶる多く、これひとつで、wmvもrmも表示できてしまうのだから凄い! 数多あるMedia Playerの王様と言えるだろう。

 自宅でPCを起動しているときには必ず起動しているメディアプレーヤー。何かと過剰なWinampよりも、起動も速くスキンはシンプルだ。

 DivX, Xvid, Mov, Vob, Mpeg, Mpeg4, avi, wmv, dv, などの動画をDVD-Video形式に変換できるフリーソフト。クリックするとDVD関連ソフト紹介サイト=「DVDなToolたち」なるHomepageが開きます。

----------
200710311816
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。